Re: Do slurpy parameters auto-flatten arrays?
Ingo Blechschmidt wrote: Hi, ReHi, are the following assumptions correct? I don't know in general. But see my assumptions below for comparison. They are derived from my type theoretic approach and as such might collide with Perl6's referential semantics. In particular with the auto-ref/deref and how far it follows links. sub foo ([EMAIL PROTECTED]) { @args[0] } say ~foo(a, b, c); # a foo( List of Str ) my @array = a b c d; say ~foo(@array);# a b c d (or a?) foo( Ref of Array ) # @args[0] derefs the array ref # I guess you need @args[0][0] to get a But I don't like this level of reference preservation. E.g. one then needs to know how far out the flat array resides, to use the right number of dereferencers. Here type theory doesn't constrain the definitional freedom because both interpretations are compatible with [EMAIL PROTECTED] Actually that unspecificity could be preserved, see below. say ~foo(@array, z); # a b c d (or a?) foo( Ref of Array, Str ) # @args[0] as above Here typing constrains the interpretation to be the one that needs @args[0][0] to get at a. This is slightly untrue. The problem is actually shifted to the question: How does comma handle a Ref of Array?. say ~foo([EMAIL PROTECTED]); # a foo( List of Str build from Array of Str) say ~foo(*(@array, z));# a sub bar ([EMAIL PROTECTED]) { [EMAIL PROTECTED] } say bar(1,2,3); # 3 say bar(@array); # 1 (or 4?) Type theory actually should come up with any(1|4) :) And yes, any(1|4) is a type literal and any($x,$y) is a parametric type which is fixed whenever $x and $y are. Side node: A nice test for hidden assumptions in code is to replace functions which return Any to behave randomly. A Vogon optimizer OTOH, might blow away a complete planet and return 42 everywhere :) For this very reason the default signature of the ideal sub is of course ::Any -- ::All where All is pure specificity. And---even thow I should start a 'type theory foundations of Perl6' thread, I mention it here---the ideal method is ::All . ::Any -- ::All A multi sub/method is in that view a *metric* dispatcher on the middle ::Any between the selector before the dot and the return type after the arrow. say bar(@array, z);# 2 (or 5?) I opt for 2. say bar([EMAIL PROTECTED]);# 4 Yep. -- TSa (Thomas Sandlaß)
block owner, topic and the referential environment
This is another spin-off from the 'Exposing the Garbage Collector' thread. Here is an enhanced version. I wonder how the generic, lexically scoped invocant/owner is called. I propose to call it $/ (other option is to call it $)and let the former topicalizer become block owners and $_ the block topic that flows into blocks from further outside if not explicitly bound with - like: $topic := Some.new; $_ := $topic; for @objects { .action } # call on $/ from @objects with $_ := $topic # in all loops @objects».action; # same for single action syntax # but for @objects - { .action } # means $/.action($/) because # $_ bound to dynamic block owner; # but usefull for methods that don't # use the topic, in particular accessors # and mutators # same as sub call for @objects - { action } # means action($/) because $_ := $/ # but $/ is there if action is of # type Method # but the $. @. %. and . are bound through $?SELF # in particular for @objects - { .action } # subref curried on invocant This implies that a .action means name lookup of 'action' while .action is an onboard method of $?SELF. This latter case is typically implemented with a vtbl lookup. The only drawback I see is, that the careless method programmer could be caugth in an endless .action loop if .action invokes .action explicitly on $_ where $_ := $/ from the outside. The same endless loop could of course be achieved with a free standing .action but that looks more like intention. With the lurking pitfalls an occasional check of $_ =:= $?SELF and $/ =:= $_ seems advisable and indicates that the invocant wasn't exchanged midway :) Same with other block topicalizers/owners given $x{...} # topic untouched, but $/ := $x given $x - {...} # $_ := $x as well But if $x{...} # $/ and $_ untouched if $x - {...} # $_ := $x (non boolean value) One more interessting thing is that in exception handlers all three variables $!, $/ and $_ are in scope. This might allow to resume where the exception occurred after the cause was fixed e.g. by loading or generating some code, some revamping or other DEEP_MAGIC. Hmm, debug exceptions come to mind... -- TSa (Thomas Sandlaß)
Re: Do slurpy parameters auto-flatten arrays?
On 7/26/05, Ingo Blechschmidt [EMAIL PROTECTED] wrote: Hi, are the following assumptions correct? sub foo ([EMAIL PROTECTED]) { @args[0] } say ~foo(a, b, c); # a Yep. my @array = a b c d; say ~foo(@array);# a b c d (or a?) say ~foo(@array, z); # a b c d (or a?) a for both of these. The *@ area behaves just like Perl 5's calling conventions. I could argue for never auto flattening arrays, but then there'd really be no difference between @ and $. say ~foo([EMAIL PROTECTED]); # a say ~foo(*(@array, z));# a Hmm, *(@array, z)... what does that mean? Whatever it means, you're correct in both of these. In the latter, the @array is in a flattening context, so it gets, well, flattened. sub bar ([EMAIL PROTECTED]) { [EMAIL PROTECTED] } say bar(1,2,3); # 3 say bar(@array); # 1 (or 4?) 4 say bar(@array, z);# 2 (or 5?) 5 say bar([EMAIL PROTECTED]);# 4 Yep. Luke
Re: Exposing the Garbage Collector (Iterating the live set)
On 7/26/05, TSa (Thomas Sandlaß) [EMAIL PROTECTED] wrote: Piers Cawley wrote: I would like to be able to iterate over all the objects in the live set. My Idea actually is to embedd that into the namespace syntax. The idea is that of looking up non-negativ integer literals with 0 beeing the namespace owner. for ::Namespace - $instance { if +$instance != 0 { reconfigure $instance } } Oh, so a namespace can behave as an array then. Well, to avoid auto-flattening problems in other, more common places, we ought to make that: for *::Namespace - $instance {...} However, this is very huffmanly incorrect. First of all, what you're doing may take a quarter of a second or more for a large program (which isn't a short amount of time by any means). Second, the fact that you're using it means you're doing something evil. Third, only a fraction of 1/omega perl programmers will be using this feature. Therefore, it should probably look like: use introspection; for introspection::ALL_INSTANCES(::Namespace) - $instance {...} And it might even be platform-specific, given the constraints of some of our targets. Luke
Re: Exposing the Garbage Collector (Iterating the live set)
Luke Palmer wrote: On 7/26/05, TSa (Thomas Sandlaß) [EMAIL PROTECTED] wrote: Piers Cawley wrote: I would like to be able to iterate over all the objects in the live set. My Idea actually is to embedd that into the namespace syntax. The idea is that of looking up non-negativ integer literals with 0 beeing the namespace owner. for ::Namespace - $instance { if +$instance != 0 { reconfigure $instance } } Oh, so a namespace can behave as an array then. Well, to avoid auto-flattening problems in other, more common places, we ought to make that: for *::Namespace - $instance {...} Well, even more huffmanized would be for Namespace - {...; use $_} might be what you expect after my @array = (0,1,2,3); ::Namespace ::= @array; However, this is very huffmanly incorrect. First of all, what you're doing may take a quarter of a second or more for a large program (which isn't a short amount of time by any means). Second, the fact that you're using it means you're doing something evil. Third, only a fraction of 1/omega perl programmers will be using this feature. Therefore, it should probably look like: use introspection; for introspection::ALL_INSTANCES(::Namespace) - $instance {...} This is why I wonder how writeable the namespace is, and when. On some platforms it might actually not even be readable because it was compiled away or stripped from the excecutable ;) All that remains then is the possible behaviour as it is constrained by the types of souls/daemons the creator happened to *choose*. I guess you should re-read $Luke::Bible or watch the $*::Movies::WarnerBrothers::Matrix again :)) If both refs are undef in your namespace, go and bind them! If the above is insulting, feel free to invoke my .apologize with you as topic. You know, I'm the $/ of this $email. And it might even be platform-specific, given the constraints of some of our targets. The platform is yet another restriction on Space::Search::Solution. Interestingly namespace lookup is big endian... -- $Language::Perl6::TSa.greeting (somehow we are all part of it or was that $_?)
Messing with the type heirarchy
http://repetae.net/john/recent/out/supertyping.html This was a passing proposal to allow supertype declarations in Haskell. I'm referencing it here because it's something that I've had in the back of my mind for a while for Perl 6. I'm glad somebody else has thought of it. Something that is worth looking into is Sather's type system. I haven't read anything about it yet, but worry not, I will. Anyway, on to the proposal. I've often thought that it would be very powerful to put types in-between other types in the hierarchy. This includes making existing types do your roles (which Damian describes as spooky action at a distance). Allow me to provide an example. Let's say that Perl 6 does not provide a complex number class by default. How would you go about writing one? Well, let's do the standard Perl practice of making words that your users are supposed to say in their code roles. role Complex { # implementation details are unimportant (as always :-p) } Now, where does it belong in the type heirarcy so it can interact well with standard types? It belongs *above* Num (and below whatever is above Num). Everything that is a Num is a Complex right? It just has a zero imaginary part. But currently that is impossible. So we have to define conversions, which behave quite differently from simple interface compatibilites. For one, we have to reference a concrete complex type. Basically, we've made Complex feel like an outsider to the Perl standard hierarchy. As another example, let's say I'm implementing my own Junction class, MyJunction. I want it to be lower precedence than standard Junctions (for an appropriate definition of precedence; in this case, it means it will be threaded first). Put aside for the moment how we define the multimethods for all existing subs at once. The safe way to implement a threading object is to give it its own level in the type hierarchy. For example, to do Junction, we structure the type hierarchy like so: Any |- Junction |- JunctionObject # or some other appropriate name |- Object |- ... Then we can safely define MMD variants and be sure that they won't change their semantics when derivation levels change under manhattan distance. Under pure ordering, we prevent against ambiguity errors (which is in fact how I came up with this pattern). So, anyway, to define MyJunction, I'd like the hierarchy to look like this: Any |- MyJunction |- MyJunctionObject |- Junction |- JunctionObject |- Object |- ... This is a case where it is absolutely necessary to supertype in order to achieve certain semantics. Okay, now that I have the need out of the way, the syntax is obvious: role Complex does Object contains Num {...} There is probably a better word than contains. I was thinking set theory when I came up with that one. It might be wise only to allow this for roles if we go with a derivation metric-based MMD scheme. Allowing this for classes would mean that you could add depth to the metric that the author of the classes in question didn't intend, and I've already shown that you can screw up manhattan MMD semantics at a distance, spookily, if you do that. Luke
Re: The Use and Abuse of Liskov
On 7/19/05, Damian Conway [EMAIL PROTECTED] wrote: And now maybe you see why I am so disgusted by this metric. You see, I'm thinking of a class simply as the set of all of its possible instances. There's your problem. Classes are not isomorphic to sets of instances and derived classes are not isomorphic to subsets. Ahh, I understand now. If you think that way, then there is no way to convince you, since that is the piece of mathematics that my whole argument is based on. Please seriously consider this world model and its implications (especially regarding my new thread about superclassing). I'll give up on the theoretical side now. ~ I've just released Class::Multimethods::Pure for an account of how pure ordering works in practice. As the first case study, see Class::Multimethods::Pure (it bootstraps itself :-). The ambiguities that it pointed to me turned out to be very important design-wise, and I noticed that under manhattan distance it would have silently worked and then broken (in ambiguity) later. Readers, do your best to follow along. This is pretty complex, but that's exactly what I'm arguing: that a derivation metric like Manhattan will decieve you when things get complex. The piece was the junction factoring that I described in my other thread (I use junctions in MMD to implement type junctions). At first I had this model: Object |- Junction |- Disjunction |- Conjunction |- Injunction |- Constrained |- Subtype |- PackageType |- ... And the multis defined as: multi subset (Junction, Object) {...} multi subset (Object, Junction) {...} multi subset (Junction, Junciton) {...} Which made recursive calls to subset on their constituent types. The various Junction subclasses have a logic method which knows how to evaluate the junction in boolean context. I also had: multi subset (Subtype, Object) {...} multi subset (Object, Subtype) {...} multi subset (Subtype, Subtype) {...} Then: multi subset (Package, Package) {...} Etc. for all the other non-combinatoric types, and: multi subset (Object, Object) { 0 } As the fallback. Naturally, when I called: subset(Disjunction.new(...), Subtype.new(...)) I got an ambiguity. Did you mean (Junction, Object) or (Object, Subtype)? Something was wrong with my design: I needed to structure my types to tell the MMD system which one I wanted to thread first. This is an error that you'd expect, right? I didn't tell the compiler something it needed to know. However, look at the applicable candidates: subset(Junction, Object) # 1 + 2 = 3 subset(Object, Subset) # 2 + 0 = 2 subset(Object, Object) # 2 + 2 = 4 The second variant, (Object, Subset) matches. Oh goody, it worked! Now I can go on my merry way documenting and releasing my module. Now Mr. Joe Schmoe comes along and decides that he wants to write a new subtype type -- one that accepts his new statically-analyzable subtyping language or something. He decides to reuse code and derive from the existing Subtype type. The new type hierarchy follows: Object |- Junction |- Disjunction |- Conjunction |- Injunction |- Constrained |- Subtype |- MagicSubtype# the new type |- PackageType |- ... Now look at what happens for subtype(Disjunction.new(...), MagicSubtype.new(...)): subset(Junction, Object) # 1 + 2 = 3 subset(Object, Subtype) # 2 + 1 = 3 subset(Object, Object) # 2 + 2 = 4 Oh no! An ambiguity! What the hell, Joe's just trying to extend Subtype a little, and now he has to write a specialized MMD variant just for that, which delegates *exactly* to the (Object, Subtype) variant. I'll also point out that if you remove the Constrained intermediate type, which I did (!), you also end up in ambiguity for the call subtype(Disjunction.new(...), Subtype.new(...)). And that's it. Two innocent changes, and a working program breaks into ambiguity errors. And the person who sees the ambiguity errors is not the person who wrote -- or even touched -- the multimethods. Keep in mind: these multimethods could be for internal use, so the extender may not even know they exist. Using pure ordering, we saw the ambiguity early and were forced to think about the design and come up with one that passed the tests. When I did that, I was able to factor things to avoid duplication and needless disambiguating variants[1]. It is impossible to break the new factoring by simply deriving from any class. You would have to add a new generic, like Junction, to the top in order to break existing code. Manhattan distance suffers from the same problem. See the supertyping thread for a solution :-) I'm seeing after this case study, and something that I suspected all along, that Manhattan MMD is to pure ordering as mixins are to roles. Roles don't provide any extra semantics over
Elimination of Item|Pair and Any|Junction
On Fri, Jul 22, 2005 at 03:40:34PM -0700, Larry Wall wrote: I dunno. I'm inclined to say that it should default to Item|Pair, and let people say Any explicitly if they really want to suppress autothreading. Otherwise conditionals and switches are going to behave oddly in the presence of accidental junctions. Okay. However, in that view, I suspect many builtins will be defined on Item|Pair, for example perl, clone, id, as well as various coercion builtins. Considering that builtins are Code objects but not Routines, maybe they, too, should default to Item|Pair -- except the ones that operates on junctions, of course. This leads me to think that maybe users don't really need to write down the two junctive types, under the hierarchy below: - Object - Any - Item - ...pretty much everything - Pair - Junction - num, int, str... Since junctions are still boxed objects, having the Object type to effectively mean Any|Junction seems natural (everything is an object). Also, since Any unifies Item and Pair, the rule for implicit types of argument becomes: sub ($x) { }# Item $x - $x { } # Any $x- i.e. Item|Pair but not Junction { $^x } # Any $x- i.e. Item|Pair but not Junction Does this sound sane? Thanks, /Autrijus/ pgpbsmHzHG4yc.pgp Description: PGP signature
Re: The Use and Abuse of Liskov (was: Type::Class::Haskell does Role)
I just realized something that may be very important to my side of the story. It appears that I was skimming over your example when I should have been playing closer attention: On 7/18/05, Damian Conway [EMAIL PROTECTED] wrote: Consider the following classes: class A {...} # AB class B {...} #| class C is B {...} #C D class D {...} # \ / class E is C is D {...} # E multi sub foo(A $x, B $y) { (1) } multi sub foo(A $x, C $y) { (2) } foo(A.new, E.new); Clearly this produces (2) under either Pure Ordering or Manhattan Metric. Now we change the class hierarchy, adding *zero* extra empty classes (which is surely an even stricter LSP/Meyer test-case than adding one extra empty class!) We get this: class A {...} # A B class B {...} # / \ class C is B {...} #C D class D is B {...} # \ / class E is C is D {...} # E multi sub foo(A $x, B $y) { (1) } multi sub foo(A $x, C $y) { (2) } foo(A.new, E.new); Manhattan Metric dispatch continues to produce (2), but Pure Ordering now breaks the program. Um... no it doesn't. Pure ordering continues to produce (2) as well. Here are the precise semantics of the algorithm again: A variant a is said to be _more specific than_ a variant b if: * Every type in a's signature is a subset (derived from or equal) of the corresponding type in b's signature. * At least one of these is a proper subset (not an equality). A variant is dispatched if there is a unique most specific method applicable to the given arguments. That is, there exists an applicable variant a such that for all other applicable variants x, a is more specific than x. A is equal to A, and C is a proper subset of B, therefore the latter variant is more specific than the former. Since the latter is the unique most specific variant, and it is applicable to the argument types, it is chosen. How did you think pure ordering worked? Were we arguing over different definitions of that algorithm? Luke
Re: Messing with the type heirarchy
[sorry Luke, I hit Send too soon] On 7/27/05, Luke Palmer [EMAIL PROTECTED] wrote: There is probably a better word than contains. I was thinking set theory when I came up with that one. What about derives? Aankhen
Re: Messing with the type heirarchy
Hi, Luke Palmer wrote: http://repetae.net/john/recent/out/supertyping.html This was a passing proposal to allow supertype declarations in Haskell. I'm referencing it here because it's something that I've had in the back of my mind for a while for Perl 6. I'm glad somebody else has thought of it. [...] role Complex does Object contains Num {...} I've probably misunderstood you, but...: role Complex does Object {...} Num does Complex; # That should work and DWYM, right? --Ingo -- Linux, the choice of a GNU | Wissen ist Wissen, wo man es findet. generation on a dual AMD | Athlon!|
execution platform object? gestalt?
With the recent realization of the beginnings of a PIL-Javascript emitter, it appears that my Perl6 program can run in a bizarre mix of execution environments. Forgive me if I missed this while trying to skim through the unearthly number of perl6 messages so far, but... It'd be nice if there was one central object that represented the execution platform, with various methods based on the capabilities. For example, this object, call it $*OS, could be queried to see if we can get a native Javascript class (true only when running on a JSplatform): if $*OS.can(get_javascript_class) { # I'm running on a js platform my $main_window = $*OS.get_javascript_class(Window).main; ... } The point would be to have one object that would understand the platform dependent parts, and have a consistent naming for the methods that are used by that object as the execution platform varies. This is similar to the OS-9's gestalt tables, which got smarter as the operating system had more features, but was a consistent way to ask do we have a color monitor here?. Is something like this already planned? -- Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095 merlyn@stonehenge.com URL:http://www.stonehenge.com/merlyn/ Perl/Unix/security consulting, Technical writing, Comedy, etc. etc. See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!
Re: Messing with the type heirarchy
On 7/27/05, Ingo Blechschmidt [EMAIL PROTECTED] wrote: Luke Palmer wrote: role Complex does Object contains Num {...} I've probably misunderstood you, but...: role Complex does Object {...} Num does Complex; # That should work and DWYM, right? Supposing that you can actually do that, and that Num does Complex gets executed at compile time. I didn't know you could add does declarations to classes referring to other classes (rather than making the class object do a metaclass role... though I admit that that would only be warranted by a pretty bizarre situation).
Re: Messing with the type heirarchy
HaloO, Ingo Blechschmidt wrote: I've probably misunderstood you, but...: role Complex does Object {...} Num does Complex; # That should work and DWYM, right? My 0.02: Complex should provide e.g. a + that, when called with two Nums, doesn't bother the return value to carry on a useless imaginary part. And Complex should consistently return undef when compared to other Nums or Complexes. And the Compare role shouldn't treat undef == false but as any(true|false). Otherwise funny things can happen (as was observered correctly in another thread about != applied to any Juntions). In code: if $c 3 { die if $c.does(Complex) } This is the Perl6 representation of the following sentence: If Any::$c is less then Int::3 then die if this $c does behave like a Complex. I hope $Larry likes it. BTW, is their a plain english output module planned, that would produce the above automatically? Don't question (Light ::= Particle|Wave) with a double slit! At least not if you want a deterministic answer where it actually passed. tie rant Imagine a Casino that hands out ties to players who don't have one even though the Casino is a tied area. If a Num playing in the Casino likes the imaginary standard tie it can keep it. But among Nums this imaginary tie is no differentiator. Actually other Num methods will say: A tie? I see no tie. Must be an imaginary one. In simple environments the tie might not even be applicable imaginarily. Thus it's stripped off or entrance is denied. Under all cicumstances the Num may decide how to deal with this tieing. fun: d(en)ie(d) == die in the end :) /tie rant The only question is how much effort all this is for (1) the implementor of Complex (2) the implementor of Num (3) the user of either one in isolation (4) when they come together In particular the user in (4) should be able to state his expectations in a form that is checkable by the VM. Which basically means that (1) and (2) have to state their assumptions to the VM in the same form/syntax. -- $TSa.greeting := HaloO; # mind the echo!
Re: execution platform object? gestalt?
Randal L. Schwartz wrote: This is similar to the OS-9's gestalt tables, which got smarter as the operating system had more features, but was a consistent way to ask do we have a color monitor here?. Is something like this already planned? From my bubble in the Perl6 Universe this thing is an unbound symbolic reference $::(to The Type System). Welche Gestalt es bisher angenommen hat weiss ich nicht. But it should be capable to appear in any(@form) to help all(@us) where {any(@us) != ::United::States of America}. :) -- $TSa.greeting := HaloO; # mind the echo!
Re: execution platform object? gestalt?
On Wed, Jul 27, 2005 at 07:09:41AM -0700, Randal L. Schwartz wrote: : With the recent realization of the beginnings of a PIL-Javascript : emitter, it appears that my Perl6 program can run in a bizarre mix of : execution environments. : : Forgive me if I missed this while trying to skim through the unearthly : number of perl6 messages so far, but... : : It'd be nice if there was one central object that represented the : execution platform, with various methods based on the capabilities. Yes, we'll have something like that, but... : For example, this object, call it $*OS, could be queried to see : if we can get a native Javascript class (true only when running on : a JSplatform): : : if $*OS.can(get_javascript_class) { # I'm running on a js platform : my $main_window = $*OS.get_javascript_class(Window).main; : ... : } : : The point would be to have one object that would understand the : platform dependent parts, and have a consistent naming for the methods : that are used by that object as the execution platform varies. It's not entirely clear that get_javascript_class should be considered a method of the OS and/or platform for which .can would be appropriate. The method might be supplied by the platform, or it might be supplied merely because someone somewhere said use JS and imported the behavior. So in this particular case it might be better to just say if exists get_javascript_class {...} or maybe (if it's actually the time to get the class) just try calling the routine and catch the exception, unless you're trying to second-guess ahead of time. Or ask the language loader object whether it has loaded JS. I'm just saying that the language loader doesn't necessarily have to be considered part of the OS. But that aside, yes, we'll have visiblility into $?OS (the compile-time OS) and $*OS (the run-time OS). Or maybe those are just the names, and hashes like %?OSfeature and %*OSfeature are the appropriate forms for interrogating particular items. But $*OS as an object can subsume both of those behaviors and also provide methods, so that's probably the right way to go. On the other hand, it's also not entirely clear that all platformish feature sets should make themselves visible through one name. What's an OS? Should we distinguish VM from that? Should we be able to peer through VM and OS and get at MACHINE? What if it's running on multiple machines and they want to give conflicting advice? Arguably, it's probably good to have a single access point for everything outside the VM, and OS is as good a name as anything for that, as the abstraction of the world. (Hmm, if your program is the flesh, that leaves the VM to be the devil, I guess.) However, if we do that, then it would have to be recognized that the entire Internet is hiding inside that OS bubble. So I guess the question is whether we need $?VM and $*VM as well? Or should we consider the VM to also be foreign and lump it with OS? : This is similar to the OS-9's gestalt tables, which got smarter as : the operating system had more features, but was a consistent way to : ask do we have a color monitor here?. : : Is something like this already planned? Yes, but we just need to be careful not to recreate The Registry. We're looking more for a place for everything and everything in its place, but we're still trying to understand what that means. As you say, whatever we end up with does have to be extensible, since we don't know all the places we'll want ten years from now. It seems to me that the more places we can come up with now, though, the less likely we are to have collisions later, unless our categories are artificial. That tends to argue for separating out VM from OS, and maybe COMPUTER, and NET, unless you think that NET =:= COMPUTER. Larry
Re: Elimination of Item|Pair and Any|Junction
On Wed, Jul 27, 2005 at 08:01:25PM +0800, Autrijus Tang wrote: : On Fri, Jul 22, 2005 at 03:40:34PM -0700, Larry Wall wrote: : I dunno. I'm inclined to say that it should default to Item|Pair, and : let people say Any explicitly if they really want to suppress autothreading. : Otherwise conditionals and switches are going to behave oddly in the : presence of accidental junctions. : : Okay. However, in that view, I suspect many builtins will be defined on : Item|Pair, for example perl, clone, id, as well as various coercion : builtins. Considering that builtins are Code objects but not Routines, : maybe they, too, should default to Item|Pair -- except the ones that : operates on junctions, of course. : : This leads me to think that maybe users don't really need to write down : the two junctive types, under the hierarchy below: : : - Object : - Any : - Item : - ...pretty much everything : - Pair : - Junction : - num, int, str... : : Since junctions are still boxed objects, having the Object type to : effectively mean Any|Junction seems natural (everything is an object). : : Also, since Any unifies Item and Pair, the rule for implicit types of : argument becomes: : : sub ($x) { }# Item $x : - $x { } # Any $x- i.e. Item|Pair but not Junction : { $^x } # Any $x- i.e. Item|Pair but not Junction : : Does this sound sane? Yes. The only thing I don't like about it is that any() isn't an Any. Maybe we should rename Any to Atom. Then maybe swap Item with Atom, since in colloquial English you can say that pair of people are an item. That would give us: - Object - Item - Atom - ...pretty much everything - Pair - Junction - num, int, str... which nicely distinguishes Item from Junction. On the other hand, I actually kinda dislike the word Atom for common use (too much exposure to Lisp, I guess), so maybe we just want - Object - Mumble - Item - ...pretty much everything - Pair - Junction - num, int, str... where Mumble is something like Atom/NonJunction/Unit/Scalar/[your ad here]. Larry
Re: Elimination of Item|Pair and Any|Junction
Larry~ On 7/27/05, Larry Wall [EMAIL PROTECTED] wrote: On Wed, Jul 27, 2005 at 08:01:25PM +0800, Autrijus Tang wrote: : On Fri, Jul 22, 2005 at 03:40:34PM -0700, Larry Wall wrote: : I dunno. I'm inclined to say that it should default to Item|Pair, and : let people say Any explicitly if they really want to suppress autothreading. : Otherwise conditionals and switches are going to behave oddly in the : presence of accidental junctions. : : Okay. However, in that view, I suspect many builtins will be defined on : Item|Pair, for example perl, clone, id, as well as various coercion : builtins. Considering that builtins are Code objects but not Routines, : maybe they, too, should default to Item|Pair -- except the ones that : operates on junctions, of course. : : This leads me to think that maybe users don't really need to write down : the two junctive types, under the hierarchy below: : : - Object : - Any : - Item : - ...pretty much everything : - Pair : - Junction : - num, int, str... : : Since junctions are still boxed objects, having the Object type to : effectively mean Any|Junction seems natural (everything is an object). : : Also, since Any unifies Item and Pair, the rule for implicit types of : argument becomes: : : sub ($x) { }# Item $x : - $x { } # Any $x- i.e. Item|Pair but not Junction : { $^x } # Any $x- i.e. Item|Pair but not Junction : : Does this sound sane? Yes. The only thing I don't like about it is that any() isn't an Any. Maybe we should rename Any to Atom. Then maybe swap Item with Atom, since in colloquial English you can say that pair of people are an item. That would give us: - Object - Item - Atom - ...pretty much everything - Pair - Junction - num, int, str... which nicely distinguishes Item from Junction. On the other hand, I actually kinda dislike the word Atom for common use (too much exposure to Lisp, I guess), so maybe we just want - Object - Mumble - Item - ...pretty much everything - Pair - Junction - num, int, str... where Mumble is something like Atom/NonJunction/Unit/Scalar/[your ad here]. While we are talking about words... I dislike having Object encompass Juction. I get the feeling that some people will write functions that take Objects and not expect Junctions to slip in. I suppose that could be one of those hurdles that developers just have to jump, but it doesn't feel like it should be. Matt -- Computer Science is merely the post-Turing Decline of Formal Systems Theory. -Stan Kelly-Bootle, The Devil's DP Dictionary
Re: Elimination of Item|Pair and Any|Junction
On Wed, Jul 27, 2005 at 12:19:10PM -0400, Matt Fowles wrote: While we are talking about words... I dislike having Object encompass Juction. I get the feeling that some people will write functions that take Objects and not expect Junctions to slip in. I suppose that could be one of those hurdles that developers just have to jump, but it doesn't feel like it should be. Er, but Junctions take methods, the same way Objects do, so if there is an Object in the type hierarchy, Junction probably belongs to it. However we can tone down the ordinariness of Object so people will be less inclined to use it. Boxed? Thanks, /Autrijus/ pgpO521iJVLcV.pgp Description: PGP signature
Re: Elimination of Item|Pair and Any|Junction
HaloO, Larry Wall wrote: Yes. The only thing I don't like about it is that any() isn't an Any. Maybe we should rename Any to Atom. Then maybe swap Item with Atom, since in colloquial English you can say that pair of people are an item. Since we are in type hierachies these days, here's my from ::Any towards ::All version. The bottom part where everything finds together is missing for this installment. ::Any ... | .. ___:_|_:static type : | : | : | | = context : Package: | : Void Bool : | : | :. Module: | ___|___: | | | : | Class Grammar : | |___| : | | : | Role : Object : | : | || | : Code @Array %Hash $Item : | // | with: | TupleRecord | invocant(s) : || :/ \__ __|_ |: | |\ / || | | | .Method : Sub Block | | Inf Undef Match Junction /|: |\ | | / |: | \Ref[Code]| Rule |: | Macro| |:_/|__/|\ |: | | | | | Multi : | ~Str +Num \Ref :Pair ..: | | | |\| | |Int| \ | ___/| | | | Entry[::T where T.does(Hash)] | | | |/|\| *List Pipe =Iterator Enum ?Bit Pos[::T where T.does(Str|Array)] |\___ | | | **Eager Lazy Ref[Array|Hash] any() == lub( all --- any ) == glb( any -- all ) lesser -- greater all() == glb( all --- any ) == lub( any -- all ) Some operators and prefixes are added in to show their relation to the corresponding type. I hope it looks familiar. Here is some pseudo code that describes a bare minimum data layout required to support the respective types. type Item[::T] { has $.value of T; } type Pair[::T] { has $.key; has $.value of T; } type Tuple[::T where T does lub( @.values )] # lub = least upper bound { has @.values of T; has $.value ::= @.values; # auto-enreference for Item subtyping has T $.head ::= @.values[0]; has T $.tail ::= @.values[-1]; } type Record[::T where T does lub( @.values )] { has @.keys; has @.values of Pair[T]; has @.pairs ::= { zip @.keys, @.values }; has $.value ::= @.pairs; } type Code { has %.MY;# lexical scratchpad has .block; has $.value ::= { use %.MY; .block() }; # coderef literal } type Junction[::T where enum any all one none] { has @.values; has Junction $.value ::= { @.values as Junction[T] }; has .evaluate ::= ::JUNCTION_MAGIC; # what's the exact type of this? } -- $TSa.greeting := HaloO; # mind the echo!
Re: Messing with the type heirarchy
On Wed, Jul 27, 2005 at 11:00:20AM +, Luke Palmer wrote: : Let's say that Perl 6 does not provide a complex number class by : default. How would you go about writing one? Well, let's do the : standard Perl practice of making words that your users are supposed to : say in their code roles. : : role Complex { : # implementation details are unimportant (as always :-p) : } : : Now, where does it belong in the type heirarcy so it can interact well : with standard types? It belongs *above* Num (and below whatever is : above Num). Everything that is a Num is a Complex right? Not according to Liskov. Num is behaving more like a constrained subtype of Complex as soon as you admit that isa is about both implementation and interface. By the interface definition it's slightly truer to say that Complex is a Num because it extends Num's interface. But this is one of the standard OO paradoxes, and we're hoping roles are the way out of it. (Or to be less precise and more accurate, we're hoping it's the way to sweep the problem under N carpets where N is greater than 0 most of the time.) Larry
Re: Elimination of Item|Pair and Any|Junction
On Wed, Jul 27, 2005 at 06:28:22PM +0200, TSa (Thomas Sandlaß) wrote: : Since we are in type hierachies these days, here's my from ::Any : towards ::All version. That's pretty, but if you don't move Junction upward, you haven't really addressed the question Autrijus is asking. We're looking for a simple type name that means none(Junction) for use as the default type of the $x parameter to - $x {...}. Whatever we call it, this type/class/role/subtype has to admit Item and Pair objects but not Junctions. (And if that's the wrong way to think about it, please tell us why.) Larry
Re: Elimination of Item|Pair and Any|Junction
Larry Wall wrote: On Wed, Jul 27, 2005 at 06:28:22PM +0200, TSa (Thomas Sandlaß) wrote: : Since we are in type hierachies these days, here's my from ::Any : towards ::All version. That's pretty, but if you don't move Junction upward, you haven't really addressed the question Autrijus is asking. We're looking for a simple type name that means none(Junction) for use as the default type of the $x parameter to - $x {...}. Whatever we call it, this type/class/role/subtype has to admit Item and Pair objects but not Junctions. (And if that's the wrong way to think about it, please tell us why.) Suggestions: Definite Singelton (but that may mean no pairs, oops) Solid Settled NonJunctive (yuck) Terminal NonThreaded (yuck) Simple (but that could exclude arrays and hashs)] Basic Interesting question: are junctions infectious, are class object that include a member with ajunction type also junctions? -- [EMAIL PROTECTED] [EMAIL PROTECTED]
Re: Elimination of Item|Pair and Any|Junction
On Wed, Jul 27, 2005 at 09:12:00AM -0700, Larry Wall wrote: Yes. The only thing I don't like about it is that any() isn't an Any. snip - Object - Mumble - Item - ...pretty much everything - Pair - Junction - num, int, str... Hrm. I thought the original motivation of forcing people to write Any|Junction was precisely to discourage people from accidentally write sub foo (Any $x) and have $x accept a Junction. In other words, any() should not be of type Any. Hence it still feels natural for me that Any occurs at the position of Mumble. Thanks, /Autrijus/ pgplBqGItv0yM.pgp Description: PGP signature
Re: Elimination of Item|Pair and Any|Junction
At 9:12 AM -0700 7/27/05, Larry Wall wrote: Yes. The only thing I don't like about it is that any() isn't an Any. Maybe we should rename Any to Atom. Then maybe swap Item with Atom, since in colloquial English you can say that pair of people are an item. That would give us: - Object - Item - Atom - ...pretty much everything - Pair - Junction - num, int, str... which nicely distinguishes Item from Junction. On the other hand, I actually kinda dislike the word Atom for common use (too much exposure to Lisp, I guess), so maybe we just want - Object - Mumble - Item - ...pretty much everything - Pair - Junction - num, int, str... where Mumble is something like Atom/NonJunction/Unit/Scalar/[your ad here]. At 11:35 AM -0700 7/27/05, Larry Wall wrote: We're looking for a simple type name that means none(Junction) for use as the default type of the $x parameter to - $x {...}. Whatever we call it, this type/class/role/subtype has to admit Item and Pair objects but not Junctions. (And if that's the wrong way to think about it, please tell us why.) Between what you've said, I prefer the top diagram myself. Where something and Pair are each Item. Item seems more generic, and is what one often calls a constituent of a list being iterated through. So the $x parameter to - $x {...} should be called Item. So then the question is what to replace Atom with: - Object - Item - Mumble - ...pretty much everything - Pair - Junction - num, int, str... In my brainstorming, I found it is a lot easier to come up with words that mean single than non-junction. So working from that perspective ... Why don't we just call it a Single? - Object - Item - Single - ...pretty much everything - Pair - Junction - num, int, str... The noun Single is common in speech, unambiguous in meaning, and looks visually distinct from all the other types. It is often used side by side in speech, such as she is a single and they are a pair. Also, Single doesn't suggest being indivisible like Atom does. I also vote against the use of Scalar there, since Scalar seems too specific. Likewise with NonJunction, if we can help it, because it looks messy. -- Darren Duncan
Re: Elimination of Item|Pair and Any|Junction
On Wed, Jul 27, 2005 at 12:19:10PM -0400, Matt Fowles wrote: : While we are talking about words... I dislike having Object encompass : Juction. I get the feeling that some people will write functions that : take Objects and not expect Junctions to slip in. I suppose that : could be one of those hurdles that developers just have to jump, but : it doesn't feel like it should be. In which case - Any - Object - Item - ...pretty much everything - Pair - Junction - num, int, str... would be a little more like Thomas's type lattice. (Though I expect he'd treat the value types as constrained subtypes of Num, Int, Str, etc.) It seems stupid to split Object into just two things. But maybe there are other magical beasties like Pair that go alongside Pair, such as ordinary lazily bound argument lists before they are bound to a particular signature, or semicolons/pipes before it's determined if the signature is semicolon-sensitive. Basically, anything that's magical to the binder goes on that level, and according to the above would be an Object but not an Item. However we do it, we can only aim for Least Surprise, since No Surprise is not really attainable here. Larry
Re: execution platform object? gestalt?
LW == Larry Wall [EMAIL PROTECTED] writes: LW Yes, but we just need to be careful not to recreate The Registry. LW We're looking more for a place for everything and everything in LW its place, but we're still trying to understand what that means. LW As you say, whatever we end up with does have to be extensible, LW since we don't know all the places we'll want ten years from now. LW It seems to me that the more places we can come up with now, though, LW the less likely we are to have collisions later, unless our categories LW are artificial. That tends to argue for separating out VM from OS, LW and maybe COMPUTER, and NET, unless you think that NET =:= COMPUTER. then why not name it something like *?ENV (not to be confused with the shell/exec env which is still %ENV i assume)? then under that there are methods/hash entries like OS, VM, etc. it is the sum of all the (reasonably) known external things about this perl. OS seems too specific as does VM. they should just be subparts of the full env. this is also more like an intelligent Config.pm it seems. uri -- Uri Guttman -- [EMAIL PROTECTED] http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs http://jobs.perl.org
The meaning of returns
Consider this: sub id (Any $x) returns Any { return($x) } sub length (Str $y) returns Int { ... } length(id(abc)); Under standard static subtyping rules, this call will perform three different typechecks: 1) abc.does(Any) # (abc as Str) === (Any $x) in id 2) $x.does(Any)# ($x as Any) === (returns Any) in return 3) Any.does(Str) # (returns Any) === (Str $y) in length The final (returns Int) is unimportant here. Obviously, typecheck #3 fails, as Any cannot do Str. Indeed, there is no type literal in the return position that can satisfy this static typecheck for id, other than the bottom type which would be a subtype for every type. Let's call it All: sub id (Any $x) returns All { return($x) } However, had we used that, #2 will fail, as it would now be checking for $x.does(All), which is guaranteed to fail regardless of whether the check occurs at runtime (Str.does(All)) or compile time (Any.does(All)). Hence, it seems to me that there are only four ways out: A) Omit the #3 check from compile time; at runtime, use the actual type of $x. The returns type annotation will not propagate outward to the caller. At compile time, check for #2: Any.does(Any) At runtime, check for #2: abc.does(Any) check for #3: abc.does(Str) B) Omit the #2 check from both compile time and runtime; this allows us to write the returns All version. At compile time, check for #3: All.does(Str) At runtime, check for #3: abc.does(Str) C) Make the return type observe both #2 and #3 at compile time, using junctive types to pass both checks: sub id ( Any $x ) returns Any|All { return($x) } D) Make the return type observe both #2 and #3 at compile time, using type variables: sub id ( (::T) $x ) returns ::T { return($x) } At this moment, I don't have a strong preference to either; I'm more curious on whether this topic has been covered before by p6l and @Larry. Thanks, /Autrijus/ pgpRRbY7g7rEe.pgp Description: PGP signature
Re: Elimination of Item|Pair and Any|Junction
On Thu, Jul 28, 2005 at 03:55:55AM +0800, Autrijus Tang wrote: Hrm. I thought the original motivation of forcing people to write Any|Junction was precisely to discourage people from accidentally write sub foo (Any $x) and have $x accept a Junction. In other words, any() should not be of type Any. Hence it still feels natural for me that Any occurs at the position of Mumble. FWIW, if Any is to be ruled to be the top type and includes Junction, then I support Darren's proposal of Single, and maybe the Object type can be simply eliminated to Any: Any - Item - Single - Pair - Junction - int, num, str This also means that int num str will fit to Any via autoboxing. Thanks, /Autrijus/ pgpQPssdL4iZm.pgp Description: PGP signature
Re: The meaning of returns
On Thu, Jul 28, 2005 at 05:03:05AM +0800, Autrijus Tang wrote: Hence, it seems to me that there are only four ways out: Some annotations copied from discussion in #perl6: A) Omit the #3 check from compile time; at runtime, use the actual type of $x. The returns type annotation will not propagate outward to the caller. At compile time, check for #2: Any.does(Any) At runtime, check for #2: abc.does(Any) check for #3: abc.does(Str) This is the view that says (returns Foo) amounts to declare a: my sub return (Foo $x) { *return($x) } and perform no static checking for return types to match their calling context. It's got the dynamic language feel, which means practically no nontrivial type errors will happen at compile time, because function calls, regardless of its declared return type, can be used in any type context. B) Omit the #2 check from both compile time and runtime; this allows us to write the returns All version. At compile time, check for #3: All.does(Str) At runtime, check for #3: abc.does(Str) This is quite absurd, and was included only for completeness. C) Make the return type observe both #2 and #3 at compile time, using junctive types to pass both checks: sub id ( Any $x ) returns Any|All { return($x) } This is similar to the approach taken by OO-style local type inferencers; see the Colored local type inference paper for details. The idea is that, if one omits the returns declaration from a function of undecidable type, the inferencer can silently fill in (Any|All) and make the program compile, effectively defer typechecks to runtime. On the other hand, if the user does provide a type annotation, then both #2 and #3 will be observed, and type errors can occur. It's closer to the soft typing or incremental typing idea. D) Make the return type observe both #2 and #3 at compile time, using type variables: sub id ( (::T) $x ) returns ::T { return($x) } And this is a natural extension to guide the inferencer so it won't be totally giving up on polymorphic functions such as id. C) and D) can be taken together, resulting to a powerful soft typed language. However, if we take the view that type annotation are merely storage allocation hints and runtime coercers, then A) is probably the way to go. Thanks, /Autrijus/ pgpcVsbqfgSlq.pgp Description: PGP signature
Re: execution platform object? gestalt?
On Wed, Jul 27, 2005 at 04:27:15PM -0400, Uri Guttman wrote: : then why not name it something like *?ENV (not to be confused with the : shell/exec env which is still %ENV i assume)? Of course, the fact that you have to say not to be confused with can be taken as indicating that people will in fact confuse them... Larry
Re: execution platform object? gestalt?
LW == Larry Wall [EMAIL PROTECTED] writes: LW On Wed, Jul 27, 2005 at 04:27:15PM -0400, Uri Guttman wrote: LW : then why not name it something like *?ENV (not to be confused with the LW : shell/exec env which is still %ENV i assume)? LW Of course, the fact that you have to say not to be confused with LW can be taken as indicating that people will in fact confuse them... you could do it even worse by making the shell env be a method/entry of the perl env (bad syntax ahead): *?ENV.ENVPATH but my original point stands in that all this is should be under one builtin and it shouldn't be OS or VM. those should be parts of it and maybe shell env should be part of it too. this thingy should encompass all about this perl and the world it is in and the shell env is part of that. so other choices are the common and lame INFO and CONF. too bad ENV was taken already. i wish we could invent new words. :) bad idea: call it *?WALL cause everything is hanging on the wall. uri -- Uri Guttman -- [EMAIL PROTECTED] http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs http://jobs.perl.org
Re: The meaning of returns
On Thu, Jul 28, 2005 at 05:57:28AM +0800, Autrijus Tang wrote: On Thu, Jul 28, 2005 at 05:03:05AM +0800, Autrijus Tang wrote: Hence, it seems to me that there are only four ways out: Some annotations copied from discussion in #perl6: Last time I reply to myself on this thread, hopefully. :-) B) Omit the #2 check from both compile time and runtime; this allows us to write the returns All version. At compile time, check for #3: All.does(Str) At runtime, check for #3: abc.does(Str) This is quite absurd, and was included only for completeness. On second thought, this is not as absurd as it seems. This view is that sub f () returns Foo means f() can be used in any place that a Foo literal can occur, which means that it can be used in contexts that demands a supertype of Foo (like Any), but never a subtype of Foo. The language defined this way would still be dynamic; disabling #2 means that the type of $x will not be checked against Foo upon return($x), so anything at all can be used in that position. Meaningful type errors can occur, for example when saying close(length(abc)), where length would have returns Int and close have a IO parameter. However, this does require the curious device of returns All as the default return type, unless we eliminate that using type variables and/or type inferencing, at which time we can get #2 back for free and implement full static typechecking anyway. Thanks, /Autrius/ pgpaH5X3qHeTw.pgp Description: PGP signature
Re: execution platform object? gestalt?
On Jul 27, 2005, at 6:18 PM, Uri Guttman wrote: this thingy should encompass all about this perl and the world it is in and the shell env is part of that. How about *?PERL ? if ( *?PERL.COMPILED_OS eq 'Unix') {...} if ( *?PERL.CURRENT_OS eq 'Unix') {...} *?PERL.Grammars{Regex} = $my_bizarre_new_regex_grammar; etc. --Dks
lazy list syntax?
How can I create a lazy list from an object? I have an object representing the sequence 1..Inf. I tried creating a Coroutine, and then assigning the Coroutine to an Array, but it only yielded 1: my @a = $span.lazy; # 1 The coroutine worked fine in a while loop, but it didn't work in a for loop. This is the implementation (in ext/Span): coro lazy ($self: ) { my $iter = $self.iterator(); loop { my $n = $iter.next; return unless defined $n; yield $n; } } I understand that this is not fully specified yet, but I'd like to start writing some tests for it. Thanks! - Flavio S. Glock
An idea for doing pack.
Last night I had an idea about a possable pack API. Most likely when Pugs gets signifigently powerfull I will attempt to implement it. However I would like everyones input, below is a draft of its POD. =head1 NAME Pack - (un)pack structures as defined by a Template =head1 SYNOPSIS my Pack $template = Pack::compile {uint8 rat32}; my $string = pack($template, 244, 3.14); my @unpack = unpack($template, $string); =head1 ABSTRACT This perl library defines a declarative minilanuage that allows the conversion of Perl6 variables into (and from) a string of bytes. =head1 DESCRIPTION =head2 MACROS and SUBS macro Pack::compile ($template) is parsed (/\{ Pack.template \}/) {...} This macro is used to compile a template at compile time. This may throw a execution at compile time if there is an error in the template. sub Pack::eval (Str $template) returns Pack {...} And this sub will compile a template at runtime. This may return undef and set $! if there is an error in the template. sub Pack::pack (Pack $template,[EMAIL PROTECTED]) returns Str of byte {...} This function takes a [EMAIL PROTECTED] of ordinary Perl values and converts them into a string of bytes according to the $template. If you procide more arguments then $template requires, the extra arguments are ignored. sub Pack::pack (Str $template,[EMAIL PROTECTED]) returns Str of byte {...} A convenience function, $template is compiled into a Pack object and then run on @list; sub Pack::unpack (Pack $template,Str of byte $expr) returns List {...} sub Pack::unpack (Str $template,Str of byte $expr) returns List {...} These functions do the reverse of Pack::pack =head2 THE PACK TEMPLATE DESCRIPTION LANGUAGE (PTDL) =head3 SYNTAX The template description language describes the structure of the string as a sequence of declarations. Each declaration consists of a type, an optional argument and zero or more adjectives. Also each declaration may be bound to a variable. grammar { rule template :w { [binding? declaration]* }; rule binding :w { [Perl6.variable | Perl6.literal] :=: } rule declaration :w { [\: adjective]* Perl6.name [\( argument \)]? } rule adjective :w { Perl6.name [\( argument \)]? } rule argument :w { Perl6.variable | Perl6.closure | Perl6.literal } } For example the following are valid templates $^0 :=: byte @^_ :=: str(8) @^_ :=: str($^0) $^1 :=: rat32 =head3 SEMANTICS When packing if a declaration is bound to a scalar variable then the contents of that variable are packed into the return value of pack according to the nature of that declaration. Simmerly when unpacking each declaration will set the value of the scalar it is bound to based on its nature and the value of $expr. $^number has a special meaning in PTDL $^i is the ith (zero indexed) item of @list when packing and the ith (zero indexed) item of the return array when unpacking. If a declaration is bound to an array, when packing items will be shifted out of the array and then packed according to the declaration. Simmerly when unpacking the array will have the declaration's return values pushed into it. @^_ has a special meaning in PTDL. It is an alias to @list when packing and an alias to the return array when unpacking. By default a declaration is bound to @^_ . If a declaration is bound to a literal then when packing the value of that literal is packed, when unpacking the unpacked value is discarded. The following declarations are built in. int1 int2 int4 int8 int16 int32 (aka int on 32-bit machines) int64 (aka int on 64-bit machines) uint1 (aka bit) (like vec) uint2 uint4 uint8 (aka byte) uint16 uint32 uint64 rat32 rat64 (aka rat on most architectures) rat128 str A string of bytes utf8 A number encoded using the utf8 mapping (doesn't check for bad unicode) UTF-8 A codepoint endcoded using UTF-8 noop Does nothing (though its adjectives may have side effects) hex A hexadecimal string uuencode A uuencoded string base64 A base64 encoded string base32 A base32 encoded string base16 A base16 encoded string berA ber compressed integer The following adjectives are built in. :bigend Endcode this using bigendian order :litend Endcode this using littleendian order :pad($n) Pad to $n bytes :padchar($char) Pad using $char :term($char) String is $char terminated :mvabsMove to absolute position filling with padchar if defined. :mvrelMove to relative position filling with padchar if defined. For convenience the following declarations are defined. a($n) = :pad($n) :padchar(\x00) byte A($n) = :pad($n) :padchar( ) byte b($n) = :bigend bit($n) B($n) = :litend bit($n) c = int8 C = uint8 d = rat64 f = rat32 h = :bigend hex H = :litend hex i = int I = uint l = int32 L = uint32 n = :bigend int16 N = :bigend int32 q = int64 Q = uint64 s = int16 S = uint16 u = uuencode U = UTF-8 v = :litend int16 V = :litend int32 w = ber x = :pad(1) :padchar(\x00) noop X =
Inferring (Foo of Int).does(Foo of Any)
As Perl 6's aggregate types are generics (Role that takes type parameters), the problem of type variancy naturally arises. The basic premise is that: 1. (Array of Item).does(Array of Int); # false 2. (Array of Int).does(Array of Item); # also false! Intuitively, while an (Array of Item) can store anything that an (Array of Int) can store, it cannot promise to yield a Int as the latter can. Conversely, while (Array of Int) can always yield something that does Item, it cannot promise to store any Item. Hence neither can be the subtype of the other. As another example, consider this: sub f (Foo @x) { ... } my Bar @y; One can't expect f(@y) to work, unless both Bar.does(Foo) _and_ Foo.does(Bar). To see the reason, consider Array's interface: # invariant generics role Array[of = ::t] { method FETCH (Int $idx) returns ::t { ... } method STORE (Int $idx, ::t $elm) { ... } } Note that ::t occurs at both the return position, and at the parameter position. This means what when we fetch elements from an array of @foo, it needs to be used in a context that expects a supertype of Foo. On the other hand, when we store something into @foo, the expected context is a subtype of Foo. For @y to work in both positions, Bar needs to meet both side of the demands. I think it makes sense to hold both #1 and #2, instead of favoring one side or the other. If so, then the default Array type needs to be something like (Array of Any|All), and do a coerce:as whenever an actual fetch happens. However, this rigid invariancy does not need to apply to all generic types. For example, consider this: # covariant generics role Input[of = ::t] { method READ () returns ::t { ... } } Clearly, we can have (Input of Int).does(Input of Item), since anything that can read Int can be used in places that expects Item as inputs. On the other hand, this: # contravariant generics role Output[of = ::t] { method WRITE (::t) { ... } } means that (Output of Item).does(Output of Int), as a output channel for Items can surely be used anywhere that wishes to writes out Ints. As a final example: # nonvariant generics role Contrived[of = ::t] { method NOOP () { ... } } Not only (Contrived of Int).does(Contrived of Item), the converse is also true, as the type parameter is not actually used anywhere. Hence, my proposal is that Perl 6's generics should infer its variancy, based on the signature of its methods, and derive subtyping relationships accordingly. The other alternative is do as Java does, which is assume invariancy by default, then force users to write variancy annotations, but I think that is considerably less attractive. There may be a case for inferring by default, but overridable by the user; if so there needs to be a syntax for that. Thanks, /Autrijus/ pgpBEYZkstO6X.pgp Description: PGP signature