Logo etsi

ETSI's Bug Tracker

Notice: information submitted on the ETSI issue Tracker may be incorporated in ETSI publication(s) and therefore subject to the ETSI IPR policy.

View Revisions: Issue #8113 All Revisions ] Back to Issue ]
Summary 0008113: Type traits and user defined methods
Revision 17-08-2022 07:16 by Matthias Simon
Description Type traits allow to compose behavior in a lightweight, but powerful way.

## Methods

This extensions allows to specify methods for any user defined types. The
receiver type is specified using the "for" keyword. Inside the behavior the
receiver value is accessible via "this" symbol:

        module Example {
        type integer Timestamp
        function year() for Timestamp return string {
            return int2str(1970+this/SECONDS_PER_YEAR);
        }

        control {
            const Timestamp t := 1660681400;
            log(t.year()) // logs "2022"
        }
    }


## Traits

A trait is a set of methods and can be defined using the "trait" keyword:

    trait Stringer {
        function String() charstring;
    }

A variable of a trait type can hold any value that implements the trait:

    module Example {

        type record Point2D { integer x, integer y }
        function string() for Point3D return charstring {
            return sprintf("(%d|%d)", this.x, this.y)
        }

        type record Point3D { integer x, integer y, integer z }
        function string() for Point2D return charstring {
            return sprintf("(%d|%d|%d)", this.x, this.y, this.z)
        }

        trait Stringer {
            function string() charstring;
        }

        function logPoints(Stringer s) {
            log(s.string())
        }

        control {
            var Point2D p1 := {1,2};
            var Point3D p2 := {1,2,3}

            logPoints(p1); // okay because Point2D implements Stringer trait
            logPoints(p2); // okay because Point3D also implements Stringer trait
        }
    }


## Embedding

When the field name is omitted, the field is called an embedded field:

    type integer Timestamp;
    external function year() for Timestamp return charstring;

    type record Date {
        Timestamp, // embedded field
        charstring zone // regular field
    }


An embedded field is accessible by its type name:

    var Data d := { Timestamp := 1660681400, zone := "GMT+2" };
    d.Timestamp := d.Timestamp + 3600;


Embedded fields must be unique:

    type record Date {
        Timestamp,
        Timestamp // not allowed.
    }


Methods of an embedded field are promoted and become methods of the embedding type:

    var Data d := { Timestamp := 1660681400, zone := "GMT+2" };
    log(d.year()); // year is a promoted method implemented by the Timestamp type


Conflicting promoted methods have to be resolved explicitly:

    type integer Duration;
    external function year() for Duration return charstring;

    type record Event {
        Timestamp,
        Duration
    }

    // Timestamp and Duration both provide a "year"-method. Event type need
    // to resolve this conflict explicitly:
    function year() for Event return charstring {
        return sprintf("start=%s, duration=%s", this.Timestamp, this.Duration)
    }


## Notes and Open Questions

* Should we call it "trait" or rather "interface" like in Java, C# and Go?
* Should we support default implementations for traits (requires "implements" keyword)?
Revision 17-08-2022 07:14 by Matthias Simon
Description Type traits allow to compose behavior in a lightweight, but powerful way.

Methods
-------

This extensions allows to specify methods for any user defined types. The
receiver type is specified using the "for" keyword. Inside the behaviour the
receiver value is accessable via "this" symbol:

        module Example {
        type integer Timestamp
        function year() for Timestamp return string {
            return int2str(1970+this/SECONDS_PER_YEAR);
        }

        control {
            const Timestamp t := 1660681400;
            log(t.year()) // logs "2022"
        }
    }


## Traits

A trait is a set of methods and can be defined using the "trait" keyword:

    trait Stringer {
        function String() charstring;
    }

A variable of a trait type can hold any value that implements the trait:

    module Example {

        type record Point2D { integer x, integer y }
        function string() for Point3D return charstring {
            return sprintf("(%d|%d)", this.x, this.y)
        }

        type record Point3D { integer x, integer y, integer z }
        function string() for Point2D return charstring {
            return sprintf("(%d|%d|%d)", this.x, this.y, this.z)
        }

        trait Stringer {
            function string() charstring;
        }

        function logPoints(Stringer s) {
            log(s.string())
        }

        control {
            var Point2D p1 := {1,2};
            var Point3D p2 := {1,2,3}

            logPoints(p1); // okay because Point2D implements Stringer trait
            logPoints(p2); // okay because Point3D also implements Stringer trait
        }
    }


Embedding
---------

When the field name is omitted, the field is called an embedded field:

    type integer Timestamp;
    external function year() for Timestamp return charstring;

    type record Date {
        Timestamp, // embedded field
        charstring zone // regular field
    }


An embedded field is accessable by its typename:

    var Data d := { Timestamp := 1660681400, zone := "GMT+2" };
    d.Timestamp := d.Timestamp + 3600;


Embedded fields must be unique:

    type record Date {
        Timestamp,
        Timestamp // not allowed.
    }


Methods of an embedded field are promoted and become methods of the embedding type:

    var Data d := { Timestamp := 1660681400, zone := "GMT+2" };
    log(d.year()); // year is a promoted method implemented by the Timestamp type


Conflicting promoted methods have to be resolved explicitly:

    type integer Duration;
    external function year() for Duration return charstring;

    type record Event {
        Timestamp,
        Duration
    }

    // Timestamp and Duration both provide a "year"-method. Event type need
    // to resolve this conflict explicitly:
    function year() for Event return charstring {
        return sprintf("start=%s, duration=%s", this.Timestamp, this.Duration)
    }

Notes and Open Questions
------------------------

* Should we call it "trait" or rather "interface" like in Java, C# and Go?
* Should we support default implementations for traits (requires "implements" keyword)?


MantisBT 1.2.14 [^]
Copyright © 2000 - 2024 MantisBT Team
Powered by Mantis Bugtracker