I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated. I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for. I had thought I could say (TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + TGroup @ {#identity->#one. #inverse->#reciprocal}) - {#identity. #inverse} but TraitComposition >> #- says that exclusion binds tighter than +. So in effect the above composition is the same as TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + (TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse}) In short, to remove the undesirable #identity and #inverse I have to exclude from both sides of the composition: TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} - {#identity. #inverse} + TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse} My question is this: what is the reason for - binding more tightly than +? Why is it _not_ desirable to have - distribute over +? frank
Hi frank normally it does not make sense to use two times the same trait. So I do not really understand how it could work. So now when you have two traits T1 T2 minus lets you erase selectively one message x from T1 if it is also available in T2 and without having to redefine it into the composite. Stef
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
I had thought I could say
(TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + TGroup @ {#identity->#one. #inverse->#reciprocal}) - {#identity. #inverse}
but TraitComposition >> #- says that exclusion binds tighter than +. So in effect the above composition is the same as
TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + (TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse})
In short, to remove the undesirable #identity and #inverse I have to exclude from both sides of the composition:
TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} - {#identity. #inverse} + TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse}
My question is this: what is the reason for - binding more tightly than +? Why is it _not_ desirable to have - distribute over +?
Hi Stef, Indeed you'd normally not double apply a trait. I want to do that here for explanatory purposes, to show that a field is the melding of two groups. As it turns out, this double application merely highlights my underlying issues. My problems would still be there whenever I wanted to compose traits that shared requirements. I had understood the "symmetric composition annihilates conflicting methods" in "Traits: composable units of behaviour" to mean that the composition would not have such methods _at all_. In Pharo, if you have two traits S and T, and a common method m, the composition S + T does contain m. If S and T implement m differently, the resulting m is "self traitConflict". If both S and T implement m as "self requirement", the resulting composition's m is also "self requirement". That surprised me, but it does actually make sense. It does mean that (S + T) != (S - m) + (T - m). What I'd also expected is that aliasing (say, S @ {#m -> #z}) would mean "the resulting composition does not understand m". But it does. So in my case, I had expected that TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} would result in a Trait that didn't define #identity or #inverse, and that TGroup @ {#identity->#one. #inverse->#reciprocal} would likewise not define #identity or #inverse. Then resulting composition would have no conflicts, and would simply understand #(#* #+ #negated #reciprocal #one #zero). frank On 30 May 2013, at 7:51, stephane ducasse <stephane.ducasse@free.fr> wrote:
Hi frank
normally it does not make sense to use two times the same trait. So I do not really understand how it could work.
So now when you have two traits T1 T2
minus lets you erase selectively one message x from T1 if it is also available in T2 and without having to redefine it into the composite.
Stef
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
I had thought I could say
(TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + TGroup @ {#identity->#one. #inverse->#reciprocal}) - {#identity. #inverse}
but TraitComposition >> #- says that exclusion binds tighter than +. So in effect the above composition is the same as
TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + (TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse})
In short, to remove the undesirable #identity and #inverse I have to exclude from both sides of the composition:
TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} - {#identity. #inverse} + TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse}
My question is this: what is the reason for - binding more tightly than +? Why is it _not_ desirable to have - distribute over +?
On May 30, 2013, at 11:03 AM, Frank Shearar <frank.shearar@gmail.com> wrote:
Hi Stef,
Indeed you'd normally not double apply a trait. I want to do that here for explanatory purposes, to show that a field is the melding of two groups.
As it turns out, this double application merely highlights my underlying issues. My problems would still be there whenever I wanted to compose traits that shared requirements.
oki
I had understood the "symmetric composition annihilates conflicting methods" in "Traits: composable units of behaviour" to mean that the composition would not have such methods _at all_.
No. This sentence is strange. But
In Pharo, if you have two traits S and T, and a common method m, the composition S + T does contain m. If S and T implement m differently, the resulting m is "self traitConflict". If both S and T implement m as "self requirement", the resulting composition's m is also "self requirement".
for requirement this is special and not well implemented in Pharo. if you have a method T1>>m ^ 42 T2>>m ^ 66 T = T1 + T2 => you have to redefine m in T T = T1-m + T2 => you get m -> 66 Now you can also alias it: ie you give a new name to the method m You can read freezable traits because there is a nice explanation.
That surprised me, but it does actually make sense. It does mean that (S + T) != (S - m) + (T - m).
I do not know :) what I know is that (S + T) can have a conflict ion m while (S - m) + (T - m) ensure you do not have a conflict
What I'd also expected is that aliasing (say, S @ {#m -> #z}) would mean "the resulting composition does not understand m". But it does.
No this is just aliasing not renaming because we cannot resolve statically renaming in dynamic language.
So in my case, I had expected that TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} would result in a Trait that didn't define #identity or #inverse, and that TGroup @ {#identity->#one. #inverse->#reciprocal} would likewise not define #identity or #inverse.
Yes I see what you mean. May be this is an implementation problem. Because we could remove the origin of the bound methods
Then resulting composition would have no conflicts, and would simply understand #(#* #+ #negated #reciprocal #one #zero).
Yes this is probably a bug of the implemantation. I do not remember what we wrote in the papers
frank
On 30 May 2013, at 7:51, stephane ducasse <stephane.ducasse@free.fr> wrote:
Hi frank
normally it does not make sense to use two times the same trait. So I do not really understand how it could work.
So now when you have two traits T1 T2
minus lets you erase selectively one message x from T1 if it is also available in T2 and without having to redefine it into the composite.
Stef
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
I had thought I could say
(TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + TGroup @ {#identity->#one. #inverse->#reciprocal}) - {#identity. #inverse}
but TraitComposition >> #- says that exclusion binds tighter than +. So in effect the above composition is the same as
TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} + (TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse})
In short, to remove the undesirable #identity and #inverse I have to exclude from both sides of the composition:
TGroup @ {#identity->#zero. #* -> #+. #inverse->#negated} - {#identity. #inverse} + TGroup @ {#identity->#one. #inverse->#reciprocal} - {#identity. #inverse}
My question is this: what is the reason for - binding more tightly than +? Why is it _not_ desirable to have - distribute over +?
Hi Frank, On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help -- Damien Cassou http://damiencassou.seasidehosting.st "Success is the ability to go from one failure to another without losing enthusiasm." Winston Churchill
On 31 May 2013 12:01, Damien Cassou <damien.cassou@gmail.com> wrote:
Hi Frank,
On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help
In explaining the problem, or an an alternative to the crazy composition? I rather think that this - which doesn't work, and prompted the question in the first place - is rather readable... _and executable_: (TGroup @ {#* -> #+. #inverse -> #negated. #identity -> #zero} + TGroup @ {#inverse -> #reciprocal. #identity -> #zero}) - {#identity. #inverse} What I don't understand is (a) why exclusion only applies to the rightmost trait in the composition and (b) why aliases either break (in Pharo [1]) or do nothing (in Squeak), where I'd expected to see implementations saying "self requirement". frank [1] https://pharo.fogbugz.com/default.asp?10803#78542
On May 31, 2013, at 1:28 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
On 31 May 2013 12:01, Damien Cassou <damien.cassou@gmail.com> wrote:
Hi Frank,
On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help
In explaining the problem, or an an alternative to the crazy composition? I rather think that this - which doesn't work, and prompted the question in the first place - is rather readable... _and executable_:
(TGroup @ {#* -> #+. #inverse -> #negated. #identity -> #zero} + TGroup @ {#inverse -> #reciprocal. #identity -> #zero}) - {#identity. #inverse}
What I don't understand is (a) why exclusion only applies to the rightmost trait in the composition and (b) why aliases either break (in Pharo [1])
do they?
or do nothing (in Squeak), where I'd expected to see implementations saying "self requirement".
we removed self requirement because it was slow to compute in interactive mode.
frank
On 31 May 2013 12:32, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
On May 31, 2013, at 1:28 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
On 31 May 2013 12:01, Damien Cassou <damien.cassou@gmail.com> wrote:
Hi Frank,
On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help
In explaining the problem, or an an alternative to the crazy composition? I rather think that this - which doesn't work, and prompted the question in the first place - is rather readable... _and executable_:
(TGroup @ {#* -> #+. #inverse -> #negated. #identity -> #zero} + TGroup @ {#inverse -> #reciprocal. #identity -> #zero}) - {#identity. #inverse}
What I don't understand is (a) why exclusion only applies to the rightmost trait in the composition and (b) why aliases either break (in Pharo [1])
do they?
I'm not sure what "they" refers to. Assuming you meant "do aliases break in Pharo?" yes they do: the alias expects the new name to already exist in the method dictionary. So if you write your trait Trait named: #TMyTrait uses: TSomething @ {#aMethod -> #notWrittenYet} category: 'Thing' then you get a KeyNotFound because TMyTrait doesn't have #notWrittenYet in its method dictionary. It should be fairly easy to fix; I just raised the ticket. If you meant "do exclusions only apply to the rightmost trait?", yes they do. The comment in both Pharo and Squeak say that - binds tighter than @ or +. That's fine. To me, that would mean that S + T @ {#m -> #z} - {#m} would remove #m from T. But I thought that (S + T @ {#m - #z}) - {#m} would mean "remove m from S + T @ {#m - #z}", but it doesn't. That might simply be a TraitComposition bug. I don't know, which is why I'm asking :)
or do nothing (in Squeak), where I'd expected to see implementations saying "self requirement".
we removed self requirement because it was slow to compute in interactive mode.
Ah, ok. Fair enough! frank
frank
Hi Frank, i am currently working improving the implementation of traits in Pharo, 2013/5/31 Frank Shearar <frank.shearar@gmail.com>
On 31 May 2013 12:32, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
On May 31, 2013, at 1:28 PM, Frank Shearar <frank.shearar@gmail.com>
wrote:
On 31 May 2013 12:01, Damien Cassou <damien.cassou@gmail.com> wrote:
Hi Frank,
On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <
frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help
In explaining the problem, or an an alternative to the crazy composition? I rather think that this - which doesn't work, and prompted the question in the first place - is rather readable... _and executable_:
(TGroup @ {#* -> #+. #inverse -> #negated. #identity -> #zero} + TGroup @ {#inverse -> #reciprocal. #identity -> #zero}) - {#identity. #inverse}
What I don't understand is (a) why exclusion only applies to the rightmost trait in the composition and (b) why aliases either break (in Pharo [1])
do they?
I'm not sure what "they" refers to. Assuming you meant "do aliases break in Pharo?" yes they do: the alias expects the new name to already exist in the method dictionary. So if you write your trait
Trait named: #TMyTrait uses: TSomething @ {#aMethod -> #notWrittenYet} category: 'Thing'
then you get a KeyNotFound because TMyTrait doesn't have #notWrittenYet in its method dictionary. It should be fairly easy to fix; I just raised the ticket.
Yes, i think this is a bug, i'll fix it.
If you meant "do exclusions only apply to the rightmost trait?", yes they do. The comment in both Pharo and Squeak say that - binds tighter than @ or +. That's fine. To me, that would mean that S + T @ {#m -> #z} - {#m} would remove #m from T. But I thought that (S + T @ {#m - #z}) - {#m} would mean "remove m from S + T @ {#m - #z}", but it doesn't. That might simply be a TraitComposition bug. I don't know, which is why I'm asking :)
It looks like a bug, a trait using (S + T @ {#m->#z}) - {#m} is the same that a trait using S + (T @ {#m->#z} - {#m}) it seems it is not respecting parentheses...
or do nothing (in Squeak), where I'd expected to see implementations saying "self requirement".
we removed self requirement because it was slow to compute in interactive mode.
Ah, ok. Fair enough!
frank
frank
On 4 June 2013 10:19, Sebastian Tleye <stleye@gmail.com> wrote:
Hi Frank, i am currently working improving the implementation of traits in Pharo,
Excellent!
2013/5/31 Frank Shearar <frank.shearar@gmail.com>
On 31 May 2013 12:32, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
On May 31, 2013, at 1:28 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
On 31 May 2013 12:01, Damien Cassou <damien.cassou@gmail.com> wrote:
Hi Frank,
On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help
In explaining the problem, or an an alternative to the crazy composition? I rather think that this - which doesn't work, and prompted the question in the first place - is rather readable... _and executable_:
(TGroup @ {#* -> #+. #inverse -> #negated. #identity -> #zero} + TGroup @ {#inverse -> #reciprocal. #identity -> #zero}) - {#identity. #inverse}
What I don't understand is (a) why exclusion only applies to the rightmost trait in the composition and (b) why aliases either break (in Pharo [1])
do they?
I'm not sure what "they" refers to. Assuming you meant "do aliases break in Pharo?" yes they do: the alias expects the new name to already exist in the method dictionary. So if you write your trait
Trait named: #TMyTrait uses: TSomething @ {#aMethod -> #notWrittenYet} category: 'Thing'
then you get a KeyNotFound because TMyTrait doesn't have #notWrittenYet in its method dictionary. It should be fairly easy to fix; I just raised the ticket.
Yes, i think this is a bug, i'll fix it.
Thanks!
If you meant "do exclusions only apply to the rightmost trait?", yes they do. The comment in both Pharo and Squeak say that - binds tighter than @ or +. That's fine. To me, that would mean that S + T @ {#m -> #z} - {#m} would remove #m from T. But I thought that (S + T @ {#m - #z}) - {#m} would mean "remove m from S + T @ {#m - #z}", but it doesn't. That might simply be a TraitComposition bug. I don't know, which is why I'm asking :)
It looks like a bug,
a trait using (S + T @ {#m->#z}) - {#m}
is the same that a trait using S + (T @ {#m->#z} - {#m})
it seems it is not respecting parentheses...
Yes, that's exactly it. frank
or do nothing (in Squeak), where I'd expected to see implementations saying "self requirement".
we removed self requirement because it was slow to compute in interactive mode.
Ah, ok. Fair enough!
frank
frank
Hi Frank, Discussing with DamienC and Stef we agree it's a bug, we will fix it. 2013/6/4 Frank Shearar <frank.shearar@gmail.com>
On 4 June 2013 10:19, Sebastian Tleye <stleye@gmail.com> wrote:
Hi Frank, i am currently working improving the implementation of traits in Pharo,
Excellent!
2013/5/31 Frank Shearar <frank.shearar@gmail.com>
On 31 May 2013 12:32, Stéphane Ducasse <stephane.ducasse@inria.fr>
wrote:
On May 31, 2013, at 1:28 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
On 31 May 2013 12:01, Damien Cassou <damien.cassou@gmail.com> wrote:
Hi Frank,
On Wed, May 29, 2013 at 11:45 PM, Frank Shearar <frank.shearar@gmail.com> wrote:
I have a Trait TGroup that requires #*, #identity and #inverse. I want to construct a TField by composing TGroup with itself. One TGroup will form the operations #*, #one, and #reciprocal while the other will form #+, #zero and #negated.
I don't want #identity or #inverse, because these apply to one operation, and it makes TField's API ambiguous. That's what TraitExclusion is for.
maybe a diagram would help
In explaining the problem, or an an alternative to the crazy composition? I rather think that this - which doesn't work, and prompted the question in the first place - is rather readable... _and executable_:
(TGroup @ {#* -> #+. #inverse -> #negated. #identity -> #zero} + TGroup @ {#inverse -> #reciprocal. #identity -> #zero}) - {#identity. #inverse}
What I don't understand is (a) why exclusion only applies to the rightmost trait in the composition and (b) why aliases either break (in Pharo [1])
do they?
I'm not sure what "they" refers to. Assuming you meant "do aliases break in Pharo?" yes they do: the alias expects the new name to already exist in the method dictionary. So if you write your trait
Trait named: #TMyTrait uses: TSomething @ {#aMethod -> #notWrittenYet} category: 'Thing'
then you get a KeyNotFound because TMyTrait doesn't have #notWrittenYet in its method dictionary. It should be fairly easy to fix; I just raised the ticket.
Yes, i think this is a bug, i'll fix it.
Thanks!
If you meant "do exclusions only apply to the rightmost trait?", yes they do. The comment in both Pharo and Squeak say that - binds tighter than @ or +. That's fine. To me, that would mean that S + T @ {#m -> #z} - {#m} would remove #m from T. But I thought that (S + T @ {#m - #z}) - {#m} would mean "remove m from S + T @ {#m - #z}", but it doesn't. That might simply be a TraitComposition bug. I don't know, which is why I'm asking :)
It looks like a bug,
a trait using (S + T @ {#m->#z}) - {#m}
is the same that a trait using S + (T @ {#m->#z} - {#m})
it seems it is not respecting parentheses...
Yes, that's exactly it.
frank
or do nothing (in Squeak), where I'd expected to see implementations saying "self requirement".
we removed self requirement because it was slow to compute in interactive mode.
Ah, ok. Fair enough!
frank
frank
participants (5)
-
Damien Cassou -
Frank Shearar -
Sebastian Tleye -
stephane ducasse -
Stéphane Ducasse