Skip to content

Clarify trait semantics #886

Open
Open
@Wilfred

Description

@Wilfred
  • you can define a constructor in a trait

  • trait T implements IFoo and trait T { require implements IFoo; } are both legal, but have slightly different meanings

  • You can call T::someStaticMethod() directly today (but this should hopefully be banned soon)

  • You can define abstract methods in traits

  • You can use __ConsistentConstruct on a trait, and it's different to a class

Activity

edwinsmith

edwinsmith commented on Jul 9, 2020

@edwinsmith
  • private methods in traits are only copied into using classes if the class doesn't have one. effectively this means a class can override a trait private method.
  • every class using a trait gets its own copy of the trait's static properties
  • but only one copy, if the trait is inherited more than once: trait T1{} trait T2{use T1;} trait T3{use T1}; class C{use T2,T3};
  • in class C{use T1,T2}, if T1+T2 define conflicting abstract methods, T1 wins... but if either T1 or T2 has a concrete method, that one wins. finally, if C has the method as well, C wins.
  • in the same example, if T1+T2 define conflicting concrete methods, it's an error unless C has the method.

but have slightly different meanings

what are the two meanings?

T::someStaticMethod()

what happens if someStaticMethod() contains language constructs (e.g. parent or access to static properties) that only work in the context of a using class?

edwinsmith

edwinsmith commented on Jul 9, 2020

@edwinsmith

private methods in traits are only copied into using classes if the class doesn't have one.

HH typechecks this with override semantics - C's concrete method must have a compatible signature with the private method in T. hhvm doesn't care (T's private method is simply hidden).

edwinsmith

edwinsmith commented on Jul 10, 2020

@edwinsmith

__CLASS__ in a trait is rewritten to the class using the trait.

Wilfred

Wilfred commented on Jul 10, 2020

@Wilfred
ContributorAuthor

T::somestaticMethod()

what happens if someStaticMethod() contains language constructs (e.g. parent or access to static properties) that only work in the context of a using class?

It throws an exception/fatals. This is why we need to ban it :)

Wilfred

Wilfred commented on Jul 10, 2020

@Wilfred
ContributorAuthor

what are the two meanings?

Given two traits:

interface IHasFoo {
  public function foo(): void;
}

trait FooWithRequire {
  require implements IHasFoo;
}

trait FooWithImplements implements IHasFoo {}

Using them:

class ExampleOne implements IHasFoo {
  use FooWithRequire;
  public function foo(): void {}
}

class ExampleTwo {
  use FooWithImplements;
  public function foo(): void {}
}

ExampleOne is required to write implements IHasFoo, whereas ExampleTwo implicitly gets implements IHasFoo from using the trait.

https://fburl.com/1810mh57 has some additional discussion.

edwinsmith

edwinsmith commented on Jul 11, 2020

@edwinsmith

IIUC, both ExampleOne and ExampleTwo end up identical -- they both have the same bases, interfaces, and methods, correct? That said, I agree there is value to only allowing ExampleOne style.

Wilfred

Wilfred commented on Jul 13, 2020

@Wilfred
ContributorAuthor

both ExampleOne and ExampleTwo end up identical

Yep, the only difference is that you're required to write implements IHasFoo for ExampleOne. At runtime they should be the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @Wilfred@edwinsmith@AndrewDiMola

        Issue actions

          Clarify trait semantics · Issue #886 · hhvm/user-documentation