# Trait aliasing syntax suggestions

- Thread: https://externals.io/message/35677
- Original archive: https://news-web.php.net/php.internals/35677
- Started by Gregory Beaver on 2008-02-21T06:55:56+00:00
- Messages: 17
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #35691 — Elizabeth M Smith — 2008-02-10T14:17:49+00:00

URL: https://externals.io/message/35677#35691 · In reply to: #35677

[snip...]
> 
> class A
> {
>     trait foo;
> }
> 
> class B
> {
>     trait foo {unset bing, bar as bing};
>     trait bar;
> }
> ?>
>
[snip...]

As long as we're discussing syntax - I rather like
class A
 {
     attach foo;
 }

 class B
 {
     attach foo {hide bing, bar as bing};
     attach bar;
 }

but that's just my opinion into the "how to do the syntax" discussion

I do like the "foo as bar" style aliasing, it will really make sense as
namespaces follow the same convention, but I think hide is more
appropriate than unset

As for attach keyword, well it's short and descriptive, you are
attaching new functionality to the class.  I think that reusing trait
both as the way to put the trait in the class and to declare the trait
will confuse people.

My $0.02

Thanks,
Elizabeth Smith

---

## #35677 — Gregory Beaver — 2008-02-21T06:55:56+00:00

URL: https://externals.io/message/35677#35677

Hi,

Here is a slightly clearer syntax for trait instantiation and for
aliasing/removing method names from traits:

<?php
trait foo
{
    function bar(){}
    function bing(){}
}

trait bar
{
    function bar(){}
}

class A
{
    trait foo;
}

class B
{
    trait foo {unset bing, bar as bing};
    trait bar;
}
?>

Simply re-using "trait" instead of "use" is a more self-documenting
solution.  I found it slightly confusing to see "use" when that is a
namespace-specific token currently.  This is also in keeping with the
way functions are defined in interfaces vs. implementation, but in
reverse (for traits, brackets are used for declaration, semi-colon used
for instantiation).

Obviously, using "unset" is more similar to current PHP ideas on how to
remove something, and the "as" syntax is also very PHP-ish, these will
be far more self-documenting than the proposed syntaxes I've read thus far.

Greg

---

## #35688 — Lukas Kahwe Smith — 2008-02-21T12:55:39+00:00

URL: https://externals.io/message/35677#35688 · In reply to: #35677

> Simply re-using "trait" instead of "use" is a more self-documenting
> solution.  I found it slightly confusing to see "use" when that is a
> namespace-specific token currently.  This is also in keeping with the
> way functions are defined in interfaces vs. implementation, but in
> reverse (for traits, brackets are used for declaration, semi-colon  
> used
> for instantiation).

I like "trait" instead of "use" or any of the other proposals as well

> Obviously, using "unset" is more similar to current PHP ideas on how  
> to
> remove something, and the "as" syntax is also very PHP-ish, these will
> be far more self-documenting than the proposed syntaxes I've read  
> thus far.

Unset seems to send the wrong message again. "hide" might be better?  
As I said before "as" for aliasing is a good choice, or "alias" to  
make it even clearer.

@Stefan: are you keeping track of all the different syntax proposals?

regards,
Lukas

---

## #35689 — Lars Strojny — 2008-02-21T13:06:26+00:00

URL: https://externals.io/message/35677#35689 · In reply to: #35688

Hi,

Am Donnerstag, den 21.02.2008, 13:55 +0100 schrieb Lukas Kahwe Smith:
[...]
> I like "trait" instead of "use" or any of the other proposals as well

Do you like "class Foo class Bar" instead of "class Foo extends Bar"?
Normally PHP uses a descriptive naming scheme, while "class Foo { trait
XY; }}" would be declarative.

cu, Lars

---

## #35690 — Stefan Marr — 2008-02-21T13:43:03+00:00

URL: https://externals.io/message/35677#35690 · In reply to: #35688

> @Stefan: are you keeping track of all the different syntax proposals?
Yes, I try to keep step with all those different proposals and sum them 
  up in the end of the day.

Kind Regards
Stefan

---

## #35693 — Michael Stack — 2008-02-21T14:49:29+00:00

URL: https://externals.io/message/35677#35693 · In reply to: #35689

Hello,

What about has?

interface context {
    /* ... */
}

trait contextA implements context {
    /* ... */
}

class A {
    has contextA;
    has foobar;
}

In my opinion it is similar and descriptive like you having to implement an 
interface with implements, extend a class with 'extends' and now you have a 
trait with 'has'.

> Do you like "class Foo class Bar" instead of "class Foo extends Bar"?
> Normally PHP uses a descriptive naming scheme, while "class Foo { trait
> XY; }}" would be declarative.

---

## #35694 — Christian Schneider — 2008-02-21T15:02:38+00:00

URL: https://externals.io/message/35677#35694 · In reply to: #35677

Gregory Beaver wrote:
> Here is a slightly clearer syntax for trait instantiation and for
> aliasing/removing method names from traits:
> 
> <?php
> trait foo

...

> 
> class B
> {
>     trait foo {unset bing, bar as bing};
>     trait bar;
> }

I like the approach to reuse identifiers (trait both in declaration and
use, clearly links the two) and unset/as (avoids new keywords).

Some more thoughts:
- I've seen Stefan Marr's remarks about aliasing != renaming but the
only explanation I could find in the thread was about user perception
(along the line of "... would expect all uses of the function to be
renamed ..."). I don't think aliasing really helps here. I can see two
use cases for aliasing: 1) An interface uses a different name than the
trait implements. Not sure that's a software design problem trait should
try to solve. 2) There is a clash with an existing function in the
class. Then one would have to both alias and exclude the trait function
name anyway (which is the same as renaming) PLUS you'd have the problem
of trait classes calling the 'wrong' functions again. Maybe someone can
shed light on why aliasing is preferable to renaming after all.
- I think the whole 'how to avoid clashes' discussion is missing one
important point: Being able to override functions defined in a trait is
a *feature*, not a bug. It's the same as with inheritance, i.e. if I
override functions I can enhance but also break existing code. IMHO
Traits should be a simple mechanism giving the developer the freedom to
do the wrong thing ;-) Or more seriously: If you want to have
encapsulated functionality used in multiple places I'd use delegates a
la foo_traitemu::bar().
- The exclusion model is missing a way to include only specific
functions. To me this seems as useful as being able to exclude functions.

So my favourite solution (apart from allowing include in class
definitions ;-)) would be
trait foo { ... }
...
class B
{
	trait foo;		# All functions from foo
	trait bar(a);		# Only function a from bar
	trait qux(not b);	# Everythign but function b
	trait quux(c as d);	# Include c but rename it to d
	trait quuux(not b, c as d);	# Combination of the above
}

Note: The inclusion of specific functions acts as if a "not *" (while *
doesn't really need to be implemented neither for inclusion nor
exclusion IMHO) was given first.

Another detail: The implementation of the parser changes should still
allow a class or function called "trait", i.e. "trait" should only be a
keyword at specific positions in the source to avoid unneccesary BC
breaks. The current patch has this BC problem.

- Chris

---

## #35705 — jvlad — 2008-02-21T22:11:53+00:00

URL: https://externals.io/message/35677#35705 · In reply to: #35677

Hi,

what's about sample below?

<?php
class foo
{
    public $aabb;
    const bbaa = 'abba';
    static public $baba;
    function bar(){}
    function bing(){}
}
class bar
{
    const baab = foo::bbaa;
    function bar(){}
}

class A
{
    trait foo;
}

class B
{
    trait foo {unset bing, bar as bing, unset $aabb, unset bbaa};
    trait bar;
}
?>

in other words, why to introduce such a new thing as trait instead of using 
classes and trait'ing them?

just my two cents.
-j


"Gregory Beaver" <greg@chiaraquartet.net> wrote in message 
news:47BD207C.2080905@chiaraquartet.net...
> Hi,
>
> Here is a slightly clearer syntax for trait instantiation and for
> aliasing/removing method names from traits:
>
> <?php
> trait foo
> {
>    function bar(){}
>    function bing(){}
> }
>
> trait bar
> {
>    function bar(){}
> }
>
> class A
> {
>    trait foo;
> }
>
> class B
> {
>    trait foo {unset bing, bar as bing};
>    trait bar;
> }
> ?>
>
> Simply re-using "trait" instead of "use" is a more self-documenting
> solution.  I found it slightly confusing to see "use" when that is a
> namespace-specific token currently.  This is also in keeping with the
> way functions are defined in interfaces vs. implementation, but in
> reverse (for traits, brackets are used for declaration, semi-colon used
> for instantiation).
>
> Obviously, using "unset" is more similar to current PHP ideas on how to
> remove something, and the "as" syntax is also very PHP-ish, these will
> be far more self-documenting than the proposed syntaxes I've read thus 
> far.
>
> Greg

---

## #35707 — Stefan Marr — 2008-02-21T22:55:11+00:00

URL: https://externals.io/message/35677#35707 · In reply to: #35705

Hi,

jvlad schrieb:
> in other words, why to introduce such a new thing as trait instead of using 
> classes and trait'ing them?
I've introduced it as a separate notion from classes to avoid 
misconception and problems occurring from conflicting properties and 
constant definitions.

Your example demonstrates the week point of this approach very well in 
my eyes. Instead of allow easy reuse, you will have to manage much more 
conflicts. Think it is better to restrict the idea. Just allow to reuse 
methods trying to avoid additional conflicts which must be handled each 
time.

Another point is, think there is no benefit in duplicating constants?.

Kind Regards
Stefan

---

## #35709 — jvlad — 2008-02-21T23:12:37+00:00

URL: https://externals.io/message/35677#35709 · In reply to: #35707

"Stefan Marr" <php@stefan-marr.de> wrote in message 
news:47BE014F.5020202@stefan-marr.de...
> Hi,
>
> jvlad schrieb:
> > […]
> I've introduced it as a separate notion from classes to avoid 
> misconception and problems occurring from conflicting properties and 
> constant definitions.
>
> Your example demonstrates the week point of this approach very well in my 
> eyes. Instead of allow easy reuse, you will have to manage much more 
> conflicts. Think it is better to restrict the idea. Just allow to reuse 
> methods trying to avoid additional conflicts which must be handled each 
> time.
>
> Another point is, think there is no benefit in duplicating constants?.

Why would this create any problems? Say, you have class B that extends class 
A and both do define one method and one property under the same names. Will 
this create a problem? No. It's because there are rules that clearly 
describe how it works (method and property will be overriden). Similar 
approach may be applied to trait'ing classes. Why not? For example if you 
have a property defined above trait'ing, it will be overriden by the trait 
if it comes up with its own property with the same name (same goes for the 
properties defined in the ancestor class). If trait defines a property, it 
can be overriden by class if it introduce it below trait'ing statement.
On the other hand, if someone being a developer cares of potential 
"conflict" (unwanted override), he/she may simply not define properties and 
constants in the class that's intended to be trait'ed into another class.


Best Regards
j

---

## #35712 — Stefan Marr — 2008-02-21T23:28:47+00:00

URL: https://externals.io/message/35677#35712 · In reply to: #35709

Hi,

jvlad schrieb:
> Why would this create any problems? Say, you have class B that extends class 
> A and both do define one method and one property under the same names. Will 
> this create a problem? No. It's because there are rules that clearly 
> describe how it works (method and property will be overriden). Similar 
> approach may be applied to trait'ing classes. Why not? For example if you 
> have a property defined above trait'ing, it will be overriden by the trait 
> if it comes up with its own property with the same name (same goes for the 
> properties defined in the ancestor class). If trait defines a property, it 
> can be overriden by class if it introduce it below trait'ing statement.
> On the other hand, if someone being a developer cares of potential 
> "conflict" (unwanted override), he/she may simply not define properties and 
> constants in the class that's intended to be trait'ed into another class.
This contradicts the idea behind traits.
Here all conflicts are handled explicitly. Overriding is not used 
between traits to provide greater power and allow the notion of 
flattening in the way it has been proposed.
Your proposal is much like mixins. But mixins have limited composition 
power caused by this overriding. There are situations without a suitable 
linearization to get overlapping methods from to different mixins in the 
needed combination.

The complete argumentation can be found here: 
http://www.iam.unibe.ch/~scg/Archive/Papers/Duca06bTOPLASTraits.pdf
illustrating the cons of mixins and multiple inheritance.

Kind Regards
Stefan

---

## #35719 — Gregory Beaver — 2008-02-22T05:56:35+00:00

URL: https://externals.io/message/35677#35719 · In reply to: #35694

Christian Schneider wrote:

> So my favourite solution (apart from allowing include in class
> definitions ;-)) would be
> trait foo { ... }
> ...
> class B
> {
> 	trait foo;		# All functions from foo
> 	trait bar(a);		# Only function a from bar
> 	trait qux(not b);	# Everythign but function b
> 	trait quux(c as d);	# Include c but rename it to d
> 	trait quuux(not b, c as d);	# Combination of the above
> }

I could live with most of this as well.

"trait bar(a);" is really confusing - it looks like a function call and
is not nearly as clear as the other options.  It's unlikely to be
necessary since a trait should really only have a few functions in it
anyways.

> Note: The inclusion of specific functions acts as if a "not *" (while *
> doesn't really need to be implemented neither for inclusion nor
> exclusion IMHO) was given first.
> 
> Another detail: The implementation of the parser changes should still
> allow a class or function called "trait", i.e. "trait" should only be a
> keyword at specific positions in the source to avoid unneccesary BC
> breaks. The current patch has this BC problem.

This is not possible to implement, having tried to do a similar thing
for 'import' and 'namespace.'  The reason is that we can encounter a
classname at any point thanks to "classname::whatever" syntax, so it
slows the lexer down a bit in that for every `T_TRAIT` we would have to
check to see if the next 2 characters are ::, and makes the lexer
uber-complicated.  It's a big mess.

Greg

---

## #35721 — Lukas Kahwe Smith — 2008-02-22T07:27:08+00:00

URL: https://externals.io/message/35677#35721 · In reply to: #35719

> Another detail: The implementation of the parser changes should still
> > […]
>
> This is not possible to implement, having tried to do a similar thing
> for 'import' and 'namespace.'  The reason is that we can encounter a
> classname at any point thanks to "classname::whatever" syntax, so it
> slows the lexer down a bit in that for every `T_TRAIT` we would have to
> check to see if the next 2 characters are ::, and makes the lexer
> uber-complicated.  It's a big mess.

Not yet at any rate. From what I hear the next step after migration to  
re2c [1] is to migrate to lemon, which should make stuff like this  
possible. However while re2c has a chance of making it into PHP 5.3,  
the lemon part seems a bit further off.

regards,
Lukas

[1] http://blog.somabo.de/2008/02/php-on-re2c.html

---

## #35734 — Christian Schneider — 2008-02-22T16:53:18+00:00

URL: https://externals.io/message/35677#35734 · In reply to: #35719

Gregory Beaver schrieb:
> Christian Schneider wrote:
> > […]
> 
> This is not possible to implement, having tried to do a similar thing
> for 'import' and 'namespace.'  The reason is that we can encounter a
> classname at any point thanks to "classname::whatever" syntax, so it
> slows the lexer down a bit in that for every `T_TRAIT` we would have to
> check to see if the next 2 characters are ::, and makes the lexer
> uber-complicated.  It's a big mess.

I think this is a point we should take seriously. I see the following 
solutions:
1. Wait with the introduction until either the parser allows such an 
addition without BC break or wait for the appropriate PHP release. (Is 
5.3 the time to introduce this BC break? I don't know the current PHP 
definitions about major/minor releases)
2. Consider this issue carefully when deciding on a syntax. Maybe favour 
a syntax with fewer new keywords. Reusing keywords like "include", "as" 
or "not" come to mind.

- Chris

---

## #35761 — Stefan Marr — 2008-02-23T20:40:23+00:00

URL: https://externals.io/message/35677#35761 · In reply to: #35694

Hi,

Christian Schneider schrieb:
> I can see two
> use cases for aliasing: 
 > 1) An interface uses a different name than the
> trait implements. Not sure that's a software design problem trait should
> try to solve.
Well, no, aliasing shouldn't be used to achieve this, think it would be 
better to add some glue code to a class to fulfill a interface, i.e. add 
a new method which will call the method from the trait if the name of 
the traits method does not fit to the interface. This will avoid 
confusion about the next point you've named. (for simple situations 
exclude and aliasing will do the job as well, yes)

 > 2) There is a clash with an existing function in the
> class. Then one would have to both alias and exclude the trait function
> name anyway (which is the same as renaming) PLUS you'd have the problem
> of trait classes calling the 'wrong' functions again.
In my opinion it is not a problem, but an opportunity.

For a situation where two traits are implementing stuff which is very 
closely related and will be combined in a class you can do the following:

trait A {
   public function handle($something) {
     $this->process($something);
   }
   protected function process($something) {
     // ...
   }
}

trait B {
   protected function process($something) {
     // a method to process $something and be reused
     // interdependently at several places
   }
}

class Processor {
   use A {
     processA => process
   }
   use B {
     processB => process
   }
   protected function process($something) {
     // do combined processing using both traits methods
     $this->processA($something);
     $this->processB($something);
   }
}

Kind Regards
Stefan

---

## #35763 — Joshua Thompson — 2008-02-23T22:38:45+00:00

URL: https://externals.io/message/35677#35763 · In reply to: #35734

> > […]
> 
> I think this is a point we should take seriously. I see the following 
> solutions:
> 1. Wait with the introduction until either the parser allows such an 
> addition without BC break or wait for the appropriate PHP release. (Is 
> 5.3 the time to introduce this BC break? I don't know the current PHP 
> definitions about major/minor releases)
> 2. Consider this issue carefully when deciding on a syntax. Maybe favour 
> a syntax with fewer new keywords. Reusing keywords like "include", "as" 
> or "not" come to mind.

If the namespace patch is in PHP 5.3 (it is in the snapshots) then we 
are already introducing the new keyword `namespace` that will break BC. 
I think we can take this as reason enough to go ahead and add the 
`trait` keyword. And since we have the following complementary keywords:

  - `class` and `extends`
  - `interface` and `implements`
  - `namespace` and `use`
  - etc.

we should go ahead and introduce the complimentary keyword for `trait`, 
and it doesn't make much sense to reuse one of the other keywords. There 
are already some suggestions on Stefan's RFC, but none of them seem to 
fit as well to me. I think we should throw `import` back onto namespaces 
and use `use` with traits. The `use` or `uses` keyword is consistent 
with other implementations of traits. And if nobody likes that idea, 
what about `inline`, `inject`, `insert`, `add`, or even `+`.

I also have an idea for aliasing that I don't think anyone has thought 
of yet: reusing the `clone` keyword like so:

<?php
class Foo {
   use Bar {
     not foo1;
     clone foo1 as barFoo1;
   }
}

Cloning I think gives us the correct idea of what is actually happening: 
the entire body of method foo1 is copied to a new method called barFoo1.

Also, using `not` for exclusion also gets my vote (although I doubt my 
vote actually matters).

-- 
"Joshua Thompson" <spam.goes.in.here@gmail.com>
<http://www.schmalls.com

---

## #35790 — Derick Rethans — 2008-02-25T15:02:31+00:00

URL: https://externals.io/message/35677#35790 · In reply to: #35707

> jvlad schrieb:
> > […]
>
> I've introduced it as a separate notion from classes to avoid misconception
> and problems occurring from conflicting properties and constant definitions.

And that is something we need, as I had a hard time parsing the previous 
example without this.

Derick

-- 
Derick Rethans
http://derickrethans.nl | http://ezcomponents.org | http://xdebug.org
