Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
HaloO, John M. Dlugosz wrote: TSa Thomas.Sandlass-at-barco.com |Perl 6| wrote: multi infix:<=> (Any $lhs, A $rhs) { $lhs.STORE($rhs.clone); # or .cow if that's not automatic } $lhs.VAR.STORE. I guess I also forgot the is rw to get a binding to the caller's container not the local one of the sub. Otherwise you could write into the caller's container without rw in the sig. The issue I want to address is how easy it is to implement immutable semantics. The ref copying is sort of an annoyance there. class A { has $.a = 0; submethod BUILD ($.a) {} method inc ($self is rw:) # get at the container of { # of the caller $self = self.^new(self.a + 1); # return self.^new(self.a + 1) without the rw # sadly doesn't work for $x.inc syntax } } my A $a .= new(7); my A $b = $a; $a === $b; # true $a eqv $b; # true $a.inc; # shall behave like ++ for Int $a === $b; # false $a eqv $b; # false The spec also says that one has to use .=method to call an in-place mutator. That is $x.inc in Daniel's example should actually mean $x = $x.inc along the lines that $x++ also means $x = $x + 1. Finally combine that with the wish to allow literals of class A. Let's assume the grammar is patched to parse integer literals as As. Then with the above 7.inc gives an error because 7 is not mutable. So as I outlined before I want to care for the callers constraint. Perl 6 lacks a syntax for that. My readings have been that = just copies the ref. Unless it's a "value type" or "immutable" which just means that it doesn't matter. I'll have to read up on that some more soon. Keep us informed, please. Regards, TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
HaloO, Daniel Ruoso wrote: [ I'm using this message to reply, because I didn't receive your reply... I'm taking it from the list history... There really seems to be something wrong with this list... ] I see all your messages arrive twice. This is not specced apparently to leave room for decision in the implementation. But there's an important question to be answered before that... what is the type returned by WHICH? Isn't that up to the implementation as well? E.g. on a 32bit platform use an unsigned 32bit integer. The only things that should not happen is that you let it leak onto the value level or that WHICHes of differently typed objects are compared. With leaking to the value level I mean allowing $x.WHICH == 42 even if it is known that WHICH is implemented with a number. But it's important to keep in mind that eqv behaviour might also be overriden by the object, that might give a canonical representation that matches the other object. Ups, no object can override eqv or any other binary method. These live outside of HOW space. You can insert your dispatch targets but that's about it. On the other hand, a 'realises' trait could change the object in order that it would still match with both 'eqv' and '===', while still '~~' to an additional type. This would be done simply by creating an anonymous class that isa the original class while overriding .^does, WHICH and eqv to shadow to the original class, and then re-blessing the object to this anonymous class. I don't understand your motivation, but I think it is the obsession with object identity. You say that the object changes class, i.e. its HOW or WHAT changes while perhaps keeping its WHICH. But eqv, === and ~~ are defined outside of the class or object system. There is an inheritance order on HOW space and a subtyping order on WHAT space. Class based dispatch goes along the former, type based dispatch along the latter. The object that changes class should not be eqv or === to itself before the transition or nominal typing becomes absurd. Regards, TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
Ter, 2008-04-29 às 14:21 +0200, TSa escreveu: > Daniel Ruoso wrote: > > Not really... 'does' is a composition operation, 'realises' would be > > just a type annotation that doesn't change the actual composition. > OK, but that is not in the spec yet. To me that is like the > proposed 'like' operator but with the programmer taking full > responsibility. Like reinterpret_cast in C++. It doesn't need to be. New traits can be implemented later. > First of all assignment has copy semantics. That is after $y = $fp, > $y =:= $fp is false. I agree that It will copy the scalar, which means that later change in the value cell won't propagate to the other variable. But both cells point to the same value. $a = $b; $a === $b; # TRUE $a =:= $b; # FALSE $b = $c; $a === $b; # FALSE As opposed to $a := $b; $a === $b; # TRUE $a =:= $b; # TRUE $b = $c; $a === $b; # TRUE In the later, the scalar itself is copied, which means that both variables *are* the same scalar, and changing the cell value in one is the same as changing the cell value in the other. So... class A { has $.a; method inc { $.a++ } }; $a = A.new( a => 0); $b = $a; $b.inc(); $a.inc(); say $a.a; # 2 say $b.a; # 2 Will work as expected. > But either the HOW, the WHAT or both of $fp have to change That is true > which implies that $y === $fp can't remain true after > $fp does Point Not really... see below... > BTW, an interesting question is if a typed > binding could become invalid: >subset AntiPoint of Any where {not .^does(Point)} >my AntiPoint $ap := $fp; # fine for now >$fp does Point; # now $ap is bound to a Point which ># violates the AntiPoint constraint This is a composition error that generates an exception. It even provides enough information for a compile-time error. > > It doesn't. By definition. === only checks WHICH. > Then we must read different versions of S03. Mine has the > sentence "Two values are never equivalent unless they are > of exactly the same type." *Value types*!!! Which is not the case here, we are talking about *Object types*, also in S03: for two mutable types (object types), checks whether they have the same identity value. (For most such types the identity is simply the reference itself.) Which means that (continuing the code starting with "class A")... $a = A.new(a => 0); $b = $a; $a === $b; # TRUE $b.inc; $a === $b; # TRUE daniel
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
[ I'm using this message to reply, because I didn't receive your reply... I'm taking it from the list history... There really seems to be something wrong with this list... ] TSa wrote: > BTW, is WHICH globally unique? Or is that also an > implementation detail? This is not specced apparently to leave room for decision in the implementation. But there's an important question to be answered before that... what is the type returned by WHICH? I haven't implemented that in SMOP yet (because I have the constant identifiers that allow me to make simple pointer comparison), but I think in the low-level it will end-up being something like a native binary blob. Which means that every non-native type will, in the end, have to be reduced to native types in the WHICH call to provide a proper value for comparison. TSa wrote: > So, even though the WHICH stays the eqv check has to change: > $a = A.new( a => 0); # your class A > $b = A.new( a => 0); > $a === $b; # False, but > $a eqv $b; # True because of snapshot semantic > $b does Point; > $a eqv $b; # False because HOW or WHAT is different But it's important to keep in mind that eqv behaviour might also be overriden by the object, that might give a canonical representation that matches the other object. An implementation of the 'realises' trait could make its canonical representation unchanged. As I said earlier, 'does' is an composition operator, it will change the class composition, therefore making it a different object. On the other hand, a 'realises' trait could change the object in order that it would still match with both 'eqv' and '===', while still '~~' to an additional type. This would be done simply by creating an anonymous class that isa the original class while overriding .^does, WHICH and eqv to shadow to the original class, and then re-blessing the object to this anonymous class. TSa wrote: > But I would like to reserve infix: for a type check without > subsequent canonical value comparison. That is continuing from above >$b.inc; >$a like $b; # still true even though $a.a != $b.a It doesn't need to be part of the spec, it's a simple module that traverses .^methods to check if $a implements all methods described by $b. You might want to implement it already in other to "reserve" the name ;). daniel
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
TSa Thomas.Sandlass-at-barco.com |Perl 6| wrote: multi infix:<=> (Any $lhs, A $rhs) { $lhs.STORE($rhs.clone); # or .cow if that's not automatic } $lhs.VAR.STORE. My readings have been that = just copies the ref. Unless it's a "value type" or "immutable" which just means that it doesn't matter. I'll have to read up on that some more soon. --John
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
TSa Thomas.Sandlass-at-barco.com |Perl 6| wrote: HaloO, Daniel Ruoso wrote: Not really... 'does' is a composition operation, 'realises' would be just a type annotation that doesn't change the actual composition. OK, but that is not in the spec yet. To me that is like the proposed 'like' operator but with the programmer taking full responsibility. Like reinterpret_cast in C++. I've not gotten that far yet, but I do envision a way to test for conformance rather than mix-in to create conformance and change things around. There might be a more primitive operation for doing than than binding a capture to a signature. I also envision that this can give the compiler information that it uses to make a cached dispatch table, but this is not visible to the user. It just means that declaring your types, even "duck types" will not only give compile-time checking but speed up calling for that variable. But either the HOW, the WHAT or both of $fp have to change which implies that $y === $fp can't remain true after $fp does Point. BTW, an interesting question is if a typed binding could become invalid: subset AntiPoint of Any where {not .^does(Point)} my AntiPoint $ap := $fp; # fine for now $fp does Point; # now $ap is bound to a Point which # violates the AntiPoint constraint It's not different than my Int $y = 5; subset X of Int where { $_ < 5 } my X $x := $y; ++$y; The subset is part of the type of the item container. You alias it to something which is a different type of container. How can such aliasing ever be other than non-variant to be correct, unless the alias is read-only? That's no different than defining a symbol with container type MyTiedItem and then trying to alias it to a plain Scalar. Type mismatch in the := operation. --John
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
HaloO, Daniel Ruoso wrote: So... class A { has $.a; method inc { $.a++ } }; $a = A.new( a => 0); $b = $a; $b.inc(); $a.inc(); say $a.a; # 2 say $b.a; # 2 Will work as expected. Depends a bit on one's expectations :) So infix:<=> has shallow copy semantics. IIRC, there was once an 'is deep' trait. Otherwise one has to implement multi infix:<=> (Any $lhs, A $rhs) { $lhs.STORE($rhs.clone); # or .cow if that's not automatic } But either the HOW, the WHAT or both of $fp have to change That is true So, even though the WHICH stays the eqv check has to change: $a = A.new( a => 0); # your class A $b = A.new( a => 0); $a === $b; # False, but $a eqv $b; # True because of snapshot semantic $b does Point; $a eqv $b; # False because HOW or WHAT is different BTW, is WHICH globally unique? Or is that also an implementation detail? The snapshot check is of course type aware: class B { has $.a; method inc { $.a++ } }; $a = A.new( a => 0); # your class A $b = B.new( a => 0); # same structural type $a eqv $b; # False because of type mismatch Funnily this implies we also need a version of eqv that uses like or duck semantics. But this seems to be foreseen. Could someone post the signature to use for eqv() to make $a and $b to compare equal structurally here? Is it eqv($a, $b, :(like A, like A))? Perhaps that can be abbreviated to eqv($a, $b, :like)? Or even infix: with the rational that this always is a test not a modifying call like infix:. But I would like to reserve infix: for a type check without subsequent canonical value comparison. That is continuing from above $b.inc; $a like $b; # still true even though $a.a != $b.a Or the structural type test is similar to .does $a .like: $b; BTW, an interesting question is if a typed binding could become invalid: subset AntiPoint of Any where {not .^does(Point)} my AntiPoint $ap := $fp; # fine for now $fp does Point; # now $ap is bound to a Point which # violates the AntiPoint constraint This is a composition error that generates an exception. It even provides enough information for a compile-time error. Where is it raised? In the '$fp does Point;' statement with the error "can't compose role Point because of AntiPoint binding to $ap"? How would that change if the line read my AntiPoint $ap = $fp; # or with real assignment # after the declaration Would it say "can't compose role Point because of AntiPoint reference in $ap"? How far does that reach? I mean does the meta object system know about the constraints of all bindings and stored references to an object? Regards, TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
HaloO, Daniel Ruoso wrote: Not really... 'does' is a composition operation, 'realises' would be just a type annotation that doesn't change the actual composition. OK, but that is not in the spec yet. To me that is like the proposed 'like' operator but with the programmer taking full responsibility. Like reinterpret_cast in C++. This way, the dispatching mechanism is still the same (and still typed), but the object now also answers true to .^does(Point). But note that FoxPoint $fp = ...; $y = $fp; $y === $fp; # obviously true $fp does Point; $y === $fp; # false because of different HOW? Wrong. $fp is still the same object and $y would also answer true to .^does(Point). it's an in-place change, not a copy. you would need to do $y = $fp.clone(); First of all assignment has copy semantics. That is after $y = $fp, $y =:= $fp is false. I agree that $before := $fp; $fp does Point; $fp =:= $before; # maintain referential identity But either the HOW, the WHAT or both of $fp have to change which implies that $y === $fp can't remain true after $fp does Point. BTW, an interesting question is if a typed binding could become invalid: subset AntiPoint of Any where {not .^does(Point)} my AntiPoint $ap := $fp; # fine for now $fp does Point; # now $ap is bound to a Point which # violates the AntiPoint constraint It doesn't. By definition. === only checks WHICH. Then we must read different versions of S03. Mine has the sentence "Two values are never equivalent unless they are of exactly the same type." Regards, TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
Ter, 2008-04-29 às 11:54 +0200, TSa escreveu: > > If we are to define an operator to declare that some arbitrary object > > conforms to some API, I would think the following as saner... > > sub foo(Point $p) {...}; > > FoxPoint $fp = ...; > > $fp realises Point; > > foo($fp); > Here the spec is quite clear that 'realises' is spelled 'does'. > This is the infix operator that composes a role into an object's > class at runtime. Not really... 'does' is a composition operation, 'realises' would be just a type annotation that doesn't change the actual composition. > > This way, the dispatching mechanism is still the same (and still typed), > > but the object now also answers true to .^does(Point). > But note that > FoxPoint $fp = ...; > $y = $fp; > $y === $fp; # obviously true > $fp does Point; > $y === $fp; # false because of different HOW? Wrong. $fp is still the same object and $y would also answer true to .^does(Point). it's an in-place change, not a copy. you would need to do $y = $fp.clone(); to keep the non-typed version. > Unfortunately S03 doesn't say if === checks for the same WHAT or the > same HOW as precondition to checking the WHICH. It doesn't. By definition. === only checks WHICH. > Generally WHAT is also quite underspecced. WHAT is implementation specific, it's underspecced for that reason. > > Which means that the typed code remains typed and the feature is > > implemented as a trait that can be used to any object, thus leaving the > > fragile type inference to the code calling the method and not to the > > method that wants a stronger typing... > I don't understand what you want to say here. I mean, the code that is calling the method would be the one doing the untyped->typed mapping, not the calling sub signature (which would make the dispatch much slower). daniel
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
Ter, 2008-04-29 às 09:28 +0200, TSa escreveu: > The thing is the .^does traverses the meta information > to find the *named* concept Point. The FoxPoint in John's > example doesn't have that and thus nominally fails the > Point test. The idea is now to also have .^does *might* traverse the information as well as simply return true if the object says so. The point here is whom to delegate the association between FoxPoint and Point... If we are to define an operator to declare that some arbitrary object conforms to some API, I would think the following as saner... sub foo(Point $p) {...}; FoxPoint $fp = ...; $fp realises Point; foo($fp); This way, the dispatching mechanism is still the same (and still typed), but the object now also answers true to .^does(Point). Which means that the typed code remains typed and the feature is implemented as a trait that can be used to any object, thus leaving the fragile type inference to the code calling the method and not to the method that wants a stronger typing... daniel
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
HaloO, Daniel Ruoso wrote: .^does *might* traverse the information as well as simply return true if the object says so. Let's not regard the problem of meta level interoperation for now. That is we have *one* meta level. The spec says that .^does asks this meta system. Now the meta system does not invent the answer! The programmer of FoxPoint has to declare that explicitly via class FoxPoint does Point {...} The point here is whom to delegate the association between FoxPoint and Point... I see only two systems: the meta and the type system. The latter is still underspecced. Even more unspecced is their interrelation. If we are to define an operator to declare that some arbitrary object conforms to some API, I would think the following as saner... sub foo(Point $p) {...}; FoxPoint $fp = ...; $fp realises Point; foo($fp); Here the spec is quite clear that 'realises' is spelled 'does'. This is the infix operator that composes a role into an object's class at runtime. This way, the dispatching mechanism is still the same (and still typed), but the object now also answers true to .^does(Point). But note that FoxPoint $fp = ...; $y = $fp; $y === $fp; # obviously true $fp does Point; $y === $fp; # false because of different HOW? Unfortunately S03 doesn't say if === checks for the same WHAT or the same HOW as precondition to checking the WHICH. Generally WHAT is also quite underspecced. Which means that the typed code remains typed and the feature is implemented as a trait that can be used to any object, thus leaving the fragile type inference to the code calling the method and not to the method that wants a stronger typing... I don't understand what you want to say here. Regards, TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan
Re: Polymorphism and Representations (Was: Re: First look: Advanced Polymorphism whitepaper)
HaloO, Daniel Ruoso wrote: hrmm... I might just be overlooking something... but... sub foo (Point $p) {...} means... $signature ~~ $capture means... Point $p := $capture[0] means... $capture[0] ~~ Point means... $capture[0].^does(Point) The thing is the .^does traverses the meta information to find the *named* concept Point. The FoxPoint in John's example doesn't have that and thus nominally fails the Point test. The idea is now to also have sub foo (Point $p) {...} to mean $capture[0].^like(Point) which does a *structural* analysis. Regards, TSa. -- "The unavoidable price of reliability is simplicity" -- C.A.R. Hoare 1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan