Re: Edge case: incongruent roles
-- Original message -- From: "Jonathan Lang" <[EMAIL PROTECTED]> > Mark Biggar wrote: > > Jonathan Lang wrote: > > > They can be: > > > > > > $A > $B if $A.x > $B.x | $A.y > $B.y; > > > $A < $B if $A.x < $B.x | $A.y < $B.y; > > > > That dosn't work. > > Agreed. The above was written in haste, and contained a couple of > fatal syntax errors that I didn't intend. Try this: > > multi infix:< <= > (Complex $A, Complex $B) { > $A.x < $B.x || $A.x == $B.x && $A.y <= $B.y > } > > or > > multi infix:< <= > (Complex $A, Complex $B) { > $A == $B || pi()/2 < ($A - $B).a <= 3*pi()/2 # if $.a is > normalized to 0..2*pi() > } > > This is transitive, reflexive, and anti-symmetric. The underlying > rule for <= in English: anywhere to the west, or due south, or equal. See the following. http://www.cut-the-knot.org/do_you_know/complex_compare.shtml -- Mark Biggar [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED]
Re: Edge case: incongruent roles
Mark Biggar wrote: Jonathan Lang wrote: > They can be: > > $A > $B if $A.x > $B.x | $A.y > $B.y; > $A < $B if $A.x < $B.x | $A.y < $B.y; That dosn't work. Agreed. The above was written in haste, and contained a couple of fatal syntax errors that I didn't intend. Try this: multi infix:< <= > (Complex $A, Complex $B) { $A.x < $B.x || $A.x == $B.x && $A.y <= $B.y } or multi infix:< <= > (Complex $A, Complex $B) { $A == $B || pi()/2 < ($A - $B).a <= 3*pi()/2 # if $.a is normalized to 0..2*pi() } This is transitive, reflexive, and anti-symmetric. The underlying rule for <= in English: anywhere to the west, or due south, or equal. -- Jonathan "Dataweaver" Lang
Re: Edge case: incongruent roles
-- Original message -- From: "Jonathan Lang" <[EMAIL PROTECTED]> > TSa wrote: > > Jonathan Lang wrote: > > > If at all possible, I would expect Complex to compose Num, thus > > > letting a Complex be used anywhere that a Num is requested. > > > > This will not work. The Num type is ordered the Complex type isn't. > > The operators <, <=, > and >= are not available in Complex. > > They can be: > > $A > $B if $A.x > $B.x | $A.y > $B.y; > $A < $B if $A.x < $B.x | $A.y < $B.y; > > This also allows you to unambiguously order any arbitrary set of > complex numbers. > > Pipe dream: it would be nice if something similar to the above > (faulty) code counted as valid Perl 6 logic programming. That dosn't work. 1+2i < 2+1i then evaluates to (true | false) which is ambigious and can't be use to sort. Num."<=" as usually defined has certain properties: it's transitive: a<= && b<=c --> a <= c, it's reflexive: a<=a, it's anti-symetric: a<=b && b<=a --> a==b and it's total: one of a<=b or b<=a must hold. a
Re: Edge case: incongruent roles
Nicholas Clark wrote: Jonathan Lang wrote: > They can be: > > $A > $B if $A.x > $B.x | $A.y > $B.y; > $A < $B if $A.x < $B.x | $A.y < $B.y; > > This also allows you to unambiguously order any arbitrary set of > complex numbers. If I'm reading that correctly then there are values of $A and $B for which $A > $B and $A < $B are simultaneously true. Good point. What I meant to say was: $A > $B if $A.x > $B.x | $A.x == $B.x & $A.y > $B.y; $A < $B if $A.x < $B.x | $A.x == $B.x & $A.y < $B.y; Or, in polar coordinates, $A <= $B if pi/2 < ($A - $B).a < 3*pi/2; With the other three comparisons defined relative to that. In effect, anything that's anywhere to the east of A, as well as anything that's due north of it, counts as being greater than it. -- Jonathan "Dataweaver" Lang
Re: Edge case: incongruent roles
On Wed, Oct 18, 2006 at 06:55:16AM -0700, Jonathan Lang wrote: > TSa wrote: > >Jonathan Lang wrote: > >> If at all possible, I would expect Complex to compose Num, thus > >> letting a Complex be used anywhere that a Num is requested. > > > >This will not work. The Num type is ordered the Complex type isn't. > >The operators <, <=, > and >= are not available in Complex. > > They can be: > > $A > $B if $A.x > $B.x | $A.y > $B.y; > $A < $B if $A.x < $B.x | $A.y < $B.y; > > This also allows you to unambiguously order any arbitrary set of > complex numbers. If I'm reading that correctly then there are values of $A and $B for which $A > $B and $A < $B are simultaneously true. If so, that doesn't invalidate your statement about ordering, but there will be different orders depending on whether you order by < or > Nicholas Clark
Re: Edge case: incongruent roles
TSa wrote: Jonathan Lang wrote: > If at all possible, I would expect Complex to compose Num, thus > letting a Complex be used anywhere that a Num is requested. This will not work. The Num type is ordered the Complex type isn't. The operators <, <=, > and >= are not available in Complex. They can be: $A > $B if $A.x > $B.x | $A.y > $B.y; $A < $B if $A.x < $B.x | $A.y < $B.y; This also allows you to unambiguously order any arbitrary set of complex numbers. Pipe dream: it would be nice if something similar to the above (faulty) code counted as valid Perl 6 logic programming. Though I can imagine Num as a subtype of Complex. But I'm not sure if there are cases where this breaks down as well---the square root function comes to mind. With the root of a negative Num returning NaN or Undef of Num which are technically Nums we could save the subtyping relation. The square root function doesn't cause any problem, even if it dies when given a negative Num. What's important as far as type-checking is concerned is that it would be defined for both real and complex numbers. In the end I think the two types Num and Complex both do a number of common roles but don't have the same set of roles they do. E.g. Comparable is available only for Nums. Basic arithmetic operations like +,-,* and / are shared. The bad thing is that it will be inconvenient to use. E.g. just using Num as parameter type in a sub that does not use comparison should allow calling with a Complex even though the nominal type is incompatible. IOW, the type inferencer should determine a much more differentiated type than simple Num for the parameter. How this type is then advertised I don't know. As I've pointed out above, it's possible to define Complex such that it does the full set of comparison operators; I'm pretty sure that there's nothing that Num can do that Complex can't do as well or better. But for the sake of argument, let's say that comparison operators weren't possible for complex numbers. For the purpose of type checking, saying that role Complex does role Num except for the comparison operators would mean that saying that "Complex.does(Num)" returns false. Mind you, it could be a detailed "false" value - say, one that provides a list of every method that Num requires that Complex doesn't implement - but it would still fail the type-checking test. IMHO, it would be nice if there was some way for perl 6 to let a programmer define a subset of an existing role's interface as a new role (a reversal of the usual process, akin to "deriving" a superclass from a subclass) for those situations where the role designer didn't have the foresight to realize that a particular subset of the role might be useful on its own, and the programmer isn't in a position to hack the original designer's code. As I envision it, this _would_ modify the original role - slightly - so that it now 'does' the new subset, thus allowing type-checking that looks for the new role to accept anything that 'does' the original role. Other than expanding the range of types that the original role will match, this should have absolutely no impact on the original role's behavior. In the above example, this sort of thing would let you create a subset of Num that doesn't include the comparison operators (say, UnorderedNum), which Complex could then compose. But we're probably best off leaving this sort of thing for Perl 6.2831853 or later (see Apocalypse 1). -- Jonathan "Dataweaver" Lang
Re: Edge case: incongruent roles
HaloO, Jonathan Lang wrote: If at all possible, I would expect Complex to compose Num, thus letting a Complex be used anywhere that a Num is requested. This will not work. The Num type is ordered the Complex type isn't. The operators <, <=, > and >= are not available in Complex. Though I can imagine Num as a subtype of Complex. But I'm not sure if there are cases where this breaks down as well---the square root function comes to mind. With the root of a negative Num returning NaN or Undef of Num which are technically Nums we could save the subtyping relation. In the end I think the two types Num and Complex both do a number of common roles but don't have the same set of roles they do. E.g. Comparable is available only for Nums. Basic arithmetic operations like +,-,* and / are shared. The bad thing is that it will be inconvenient to use. E.g. just using Num as parameter type in a sub that does not use comparison should allow calling with a Complex even though the nominal type is incompatible. IOW, the type inferencer should determine a much more differentiated type than simple Num for the parameter. How this type is then advertised I don't know. Regards, TSa. --
Re: Edge case: incongruent roles
TSa wrote: Pinning the return type to Num is bad e.g. if you want multi targets like :(Complex,Complex-->Complex). Should that also numerify complex values when stored in a Num container? If yes, how? If at all possible, I would expect Complex to compose Num, thus letting a Complex be used anywhere that a Num is requested. -- Jonathan "Dataweaver" Lang
Re: Edge case: incongruent roles
HaloO, TSa wrote: I know that the return type of / could be Num in "reality" but that spoils the example. Sorry if the above is a bad example. Pinning the return type to Num is bad e.g. if you want multi targets like :(Complex,Complex-->Complex). Should that also numerify complex values when stored in a Num container? If yes, how? --
Re: Edge case: incongruent roles
HaloO, Larry Wall wrote: On Fri, Oct 13, 2006 at 04:56:05PM -0700, Jonathan Lang wrote: : Trey Harris wrote: : >All three objects happen to be Baz's, yes. But the client code doesn't : >see them that way; the first snippet wants a Foo, the second wants a Bar. : >They should get what they expect, or Baz can't be said to "do" either. : : In principle, I agree; that's how it _should_ work. I'm pointing out : that that's not how things work in practice according to the current : documentation. The current documentation already conjectures this sort of disambiguation at S12:996, I believe. Help me to get that right with a little, more concrete example. my Num $a = 5; # dynamic type is Int my Num $b = 4; say $a/$b; # 1 or 1.25? When we assume that Int is a subtype of Num and leave co- and contravariance issues of container types out of the picture and further assume the availability of dispatch targets :(Int,Int-->Int) and :(Num,Num-->Num) in multi infix: then there is a conflict between the static type information of the container and the dynamic type of the values. And it resolves to the static container type unless it is typed as Any, then the dynamic type is used. Right? I know that the return type of / could be Num in "reality" but that spoils the example. Sorry if the above is a bad example. Regards, TSa. --
Re: Edge case: incongruent roles
On Sat, Oct 14, 2006 at 07:56:24AM -0700, Jonathan Lang wrote: : Right. That _almost_ takes care of the issue; the only part left : untouched is what happens if you have two methods that can only be : disambiguated by the invocant's role, and you aren't told what the : role is. For instance: : :class DogTree does Dog does Tree { : method bark( Dog: ) { ... } : method bark( Tree: ) { ... } :} :my DogTree $x; : :$x.bark(); : : In this example, what does the dispatcher do? Never gets to the dispatcher if you write that, because you have to write "multi method" in the class to share a short name like that. The compiler's semantic analyzer will barf on such a name collision, just as if you tried to redefine a sub. But we'll leave that aside and take the "multi" as given. If there's no good reason to choose one over the other, multi semantics dictate that the most prudent course of action is to choose neither and die of ambiguity. This is documented. On the other hand, if you say one of: $x.*bark(); $x.+bark(); then the dispatcher could arguably call them both. But we haven't really talked about whether .* notation should extend to multi methods within a single class. .* is intended primarily for calling one method from each class, and if you take that view then the initial call into the class succeeds but the redispatch into the class's multi fails from ambiguity. As usual, I can argue it both ways. Could probably even locate a gripping hand or two if I tried a little harder... Larry
Re: Edge case: incongruent roles
Larry Wall wrote: Jonathan Lang wrote: : Trey Harris wrote: : >All three objects happen to be Baz's, yes. But the client code doesn't : >see them that way; the first snippet wants a Foo, the second wants a Bar. : >They should get what they expect, or Baz can't be said to "do" either. : : In principle, I agree; that's how it _should_ work. I'm pointing out : that that's not how things work in practice according to the current : documentation. The current documentation already conjectures this sort of disambiguation at S12:996, I believe. Right. That _almost_ takes care of the issue; the only part left untouched is what happens if you have two methods that can only be disambiguated by the invocant's role, and you aren't told what the role is. For instance: class DogTree does Dog does Tree { method bark( Dog: ) { ... } method bark( Tree: ) { ... } } my DogTree $x; $x.bark(); In this example, what does the dispatcher do? -- Jonathan "Dataweaver" Lang
Re: Edge case: incongruent roles
On Fri, Oct 13, 2006 at 04:56:05PM -0700, Jonathan Lang wrote: : Trey Harris wrote: : >All three objects happen to be Baz's, yes. But the client code doesn't : >see them that way; the first snippet wants a Foo, the second wants a Bar. : >They should get what they expect, or Baz can't be said to "do" either. : : In principle, I agree; that's how it _should_ work. I'm pointing out : that that's not how things work in practice according to the current : documentation. The current documentation already conjectures this sort of disambiguation at S12:996, I believe. Larry
Re: Edge case: incongruent roles
Trey Harris wrote: In a message dated Fri, 13 Oct 2006, Jonathan Lang writes: > Since Baz does both Foo and Bar, you cannot use type-checking to > resolve this dilemma. Why not? Why shouldn't this work: my Foo $obj1 = getBaz(); # object is a Baz $obj1.baz(); # Foo::baz is called my Bar $obj2 = getBaz(); # object is a Baz $obj2.baz(); # Bar::baz is called my Baz $obj3 = getBaz(); # object is a Baz $obj3.baz(); # Depends on Bob's implementation of ::Baz The first two cases would also depend on Bob's implementation of Baz: for dispatch purposes (single or multiple), the class' method takes precedence over the role's method. This is there so that the class can resolve disputes between roles, and so that the class can refine role behavior as appropriate. Short-cirtuiting past the class' method eliminates the latter option. Also, even if the first two cases did work as you say, how would I get $obj1 to call Bar::baz when it needs to? All three objects happen to be Baz's, yes. But the client code doesn't see them that way; the first snippet wants a Foo, the second wants a Bar. They should get what they expect, or Baz can't be said to "do" either. In principle, I agree; that's how it _should_ work. I'm pointing out that that's not how things work in practice according to the current documentation. (Well, 99% of the time they do; that's why this is an edge case.) If the first snippet asks for a Foo and gets handed a Baz, it receives a Baz - and then (ideally) works with those portions of Baz that behave like Foo. The problem is that roles that can be used together in theory but which conflict in practice can lead to cases where the snippet _thinks_ it's working with the Foo-like portions when it really isn't. If methods are entirely dispatched *by name* ("duck typing"), then I agree, we have a problem. But Perl 6 supposedly supports a) multiple inheritance, b) multiple dispatch, c) traits, and d) DBC. I believe the union of those requirements means that methods must be dispatched in a more sophisticated way than just looking for a matching name. This dilemma has nothing to do with dispatch entirely by name (which, incidently, is _not_ "duck typing"): even the example that I gave allowed for dispatch on the invocant (which includes multiple inheritance and access to roles), and the problem wouldn't go away if I put "multi" in front of the keywords, bringing MMD into play. (I know a guy who works in building maintenance and also does moonlighting as a computer tech. In either of his two roles, he could be said to "do windows". But what windows he does when someone asks him to do windows is disambiguated by his current role.) Thanks for the example; this will make things more concrete. role Janitor { method do_windows() { # } method sweep_floors() { # } } sub clean_up ( Janitor $joe ) { $joe.do_windows(); $joe.sweep_floors(); } role Tech { method do_windows() { # } method do_linux() ( # } } sub program ( Tech $tom, Bool $boss_is_idiot ) { if $boss_is_idiot { $tom.do_windows() } else { $tom.do_linux() } } class Moonlighter does Tech does Janitor { method do_windows() { # } } my Moonlighter $sam; clean_up($sam); # calls Moonlighter::do_windows() program($sam, :boss_is_idiot); # calls Moonlighter::do_windows() -- Jonathan "Dataweaver" Lang
Re: Edge case: incongruent roles
In a message dated Fri, 13 Oct 2006, Jonathan Lang writes: Since Baz does both Foo and Bar, you cannot use type-checking to resolve this dilemma. Why not? Why shouldn't this work: my Foo $obj1 = getBaz(); # object is a Baz $obj1.baz(); # Foo::baz is called my Bar $obj2 = getBaz(); # object is a Baz $obj2.baz(); # Bar::baz is called my Baz $obj3 = getBaz(); # object is a Baz $obj3.baz(); # Depends on Bob's implementation of ::Baz All three objects happen to be Baz's, yes. But the client code doesn't see them that way; the first snippet wants a Foo, the second wants a Bar. They should get what they expect, or Baz can't be said to "do" either. If methods are entirely dispatched *by name* ("duck typing"), then I agree, we have a problem. But Perl 6 supposedly supports a) multiple inheritance, b) multiple dispatch, c) traits, and d) DBC. I believe the union of those requirements means that methods must be dispatched in a more sophisticated way than just looking for a matching name. (I know a guy who works in building maintenance and also does moonlighting as a computer tech. In either of his two roles, he could be said to "do windows". But what windows he does when someone asks him to do windows is disambiguated by his current role.) The way things are now, it would appear that Bob's stuck. Short of rewriting one of ( Foo and foo ) or ( Bar and bar ) to use a different method name in place of baz, he can do nothing to resolve the syntactic collision between Foo and Bar while continuing to let foo and bar run properly. Duck-typing would give you this dilemma, no question about it. But I think Perl 6 is beyond duck-typing. The dilemma only arises in the context of calling .baz on a *Baz*--and Bob hasn't written the class Baz yet. The question remaining is just one of disambiguation syntax and/or what happens when Bob chooses to do nothing about disambiguation (compile-, compose- or instantiation-time error, or some arbitrary default dispatch?). Trey -- Thoughts? --