Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Larry Wall wrote: Roles cannot be derived from, so they're always final in that sense. We should probably consider them closed by default as well, or at least closed after first use. If a role specifies implementation, it's always default implementation, so overriding implementation always occurs in a class instead. Ohh, is the following illegal? role Blahh does Blubber {...} Or is that just not considered derivation but, hmm, specialisation, subtyping subroleing or some such? So, does the above produce the subtyping relation Blahh : Blubber? -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
HaloO Larry, you wrote: On Thu, Mar 31, 2005 at 06:35:06PM +0200, Thomas Sandlaß wrote: : Is typing optional in the sense that it is no syntax error but : otherwise ignored? To me this is pain but no gain :( Well, you guys keep ignoring the answer. Let me put it a bit more mathematically. The information in my X $a; is *necessary* but not *sufficient* to do method existence testing in standard Perl 6 at compile time. You can do it IFF you have the class information AND the classes are willing to cooperate in your scheme. In the current design, you can pragmatically request that all classes cooperate, and you will get the cooperation of all classes that haven't specifically been requested to be non-cooperative. This is what all the mumbo-jumbo about open/closed and final/non-final classes comes down to. That is clear, especially the part where you talk about necessary and sufficient. Please consider myself a disciple from now on :) Actually I'm not obsessed with the compile time checking but with the semantics. Which to me means that with the above declaration a method must come from *this X or its supertypes* in the scope of the declaration. To illustrate consider the following 4 cases: | state when $a.m() | declaration | is attempted | semantics +---+ 1) my $a; | $a doesn't m()| ignored or undef or exception 2) my $a; | $a does m() | call $a.m() 3) my X $a; | X doesn't m() | type error 4) my X $a; | X does m()| call most specific Xish $a.m() The semantics of case 1) will be augmented by pragma I guess. The above becomes more interesting if considering MMD. Then it must be ensured that there is exactly one unique, most specialized implementation available for handling type X. Note that this is a stronger constraint than that the dispatch would succed for the value of $a in question---and not achievable with a Manhattan metric. And one more: when the runtime system doesn't manage to find a matching X it could call into the compiler, class composer, type engine or however this subsystem is called and try to make an appropriate type and a class implementing it! And *that* is what I consider a dynamic language---or meta language on the Parrot level. Regards, -- TSa (Thomas Sandlaß)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Tue, Apr 05, 2005 at 04:00:09PM +0200, Thomas Sandlaß wrote: : Larry Wall wrote: : Roles cannot be derived from, so they're always final in that sense. : We should probably consider them closed by default as well, or at least : closed after first use. If a role specifies implementation, it's always : default implementation, so overriding implementation always occurs in a : class : instead. : : Ohh, is the following illegal? : : role Blahh does Blubber {...} : : Or is that just not considered derivation but, hmm, specialisation, : subtyping : subroleing or some such? It does composition. : So, does the above produce the subtyping relation Blahh : Blubber? It means that both .does(Blahh) and .does(Blubber) return true. It implies that Blahh contains the Blubber interface, but does not imply that it has the same default implementation. (It can, in fact, advertise that it does Blubber but mangle the Blubber interface completely if it chooses to, but that might be considered antisocial. So the compiler might feel free to issue various warnings in that case.) I, er, kinda fibbed above when I said that overriding implementation only occurs in a class. What I really meant was that, once you've declared a role, it's closed, and you can warp its meaning only via composition into some other role or class. In isolation, a role isn't really about subtyping--it's just a form of generic code. But that same purity is what makes it useful for specifying subtype relationships elsewhere. And once roles start composing other roles, it can be construed as a form of subtyping. So, basically, yes. Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Thu, Mar 31, 2005 at 01:11:37PM -0500, Aaron Sherman wrote: : If you declare a variable to be of a type (let's even say a class to be : specific), then you have hinted to the compiler as to the nature of that : variable, but nothing is certain. : : That is to say that the compiler cannot: : : * Make any type-massaging choices yet on (implicit or explicit) : method invocations : * Issue any errors based on signature miss-matches : : Ok? Yes. You might perhaps be able to get warnings on things that look like signature mismatches, but I certainly wouldn't make it mandatory, or even the default. : Now we move on to the idea of finalization. Please correct me where I : conflate finalization and openness. I'm not sure I understand the : difference at all (no, I'm certain I don't). I think you already dug this up, but no harm in reiterating: open/closed: whether you can munge the class definition itself. final/non-final: whether this is guaranteed to be a leaf node class. : We assert (don't have the docs handy, but I'll just arm-wave the syntax) : that the class is now finalized. We don't allow assertions that a particular class is final, because that's a reversed dependency. We only allow you to assert that a particular class is non-final. One way to do that is simply to derive from it. : This means any attempt to re-define the : interface of the class is a compile-time error, correct? If we let you do it, but we don't. :-) The interface can be assumed frozen by the compiler only if the entire application requests the class finalization optimization, and if by CHECK time nobody has registered a dependency on the class by either deriving from it or claiming that they will derive from it in the future. Applications with pluggable architecture should probably not request the optimization unless there is some point in time at which it can be determined that all plugins have been linked in. : What about : changing the internals of the class (e.g. changing the code associated : with a method without re-defining the signature)? That's more like the open/closed distinction, though for an open class you could also change the interface on the fly, which would invalidate some or all of your method dispatch caches. The optimizer is also in control of open/closed classes, and you may only declare that a class must remain open. You may not declare a class closed. Again, your application may ask that all closable classes be closed. Final classes are a subset of closed classes, so if the optimizer determines that it can finalize a class but not close a class, the class is not finalized either. That's not actually a big problem, because unlike with finalization, classes may only remain open by explicit declaration of the dependency, whereas classes may be implicitly made non-final by deriving from them. This is all policy of the default metaclasses. You may, of course, have other metaclasses that establish different policies. There are applications where you probably want your classes to be born closed. This may negativly impact your ability to do AOP. : Next, what are the conditions under which a class can be finalized? : : * Can we finalize a class which has non-finalized ancestors? All ancestors are by definition non-final. : * What if it has method parameters/return values or member : variables whose types are not finalized? Depends on the extent to which we support named type equivalence vs structural type equivalence, I suppose, and whether the compiler uses type name information to make assumptions about the structure. : * What if it applies roles which are not finalized? Roles cannot be derived from, so they're always final in that sense. We should probably consider them closed by default as well, or at least closed after first use. If a role specifies implementation, it's always default implementation, so overriding implementation always occurs in a class instead. Basically, in Perl 6 I think roles take on the, er, role of finalized classes in specifying immutable interfaces, to a large extent. : Obviously each one of these questions comes with a host of what happens : if questions given a yes answer : : Another question: how does finalization interact with a class's : metaclass? Does the metaclass become a const? Is the type of a metaclass : itself a finalized class? If not, can it be finalized by user code? Metaclasses can do whatever they like. They're worse than traits, if that's possible. As I say, the default metaclass is what provides the standard policies, but they can be warped in whatever direction you like, if you want everyone to hate you. : One additional wrinkle is that *anyone* is allowed to declare a : class non-cooperative (open or non-final) during *any* part of the : compilation : : ... even after it is declared final? Can't declare anything final in Standard Perl. : Will core types be
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Thomas Sandla wrote: Int|Str : Str Str : Int|Str Int|Str : Int Int : Int|Str holds. Uhh, I hardly believe that it was me writing that last night! Int|Str is of course a proper supertype of Int and Str respectively. So we really have: Str : Str|Int Int : Str|Int, which warps us back to the co-/contravar problem of polymorphic rw containers. And that doesn't help very much in achieving high flexibility under the benevolence of strong typing. Given an even more complex Any type that encompasses the general purpose types of Perl6---namely Str, Int, Num, Bool and Refs thereof--- the lazy Perl6 programmer gets what Perl5 did all the time. This is what is called Render the Illusion of Simplicity. The solution is to make the juntive supertype on the polymorphic array itself, which actually is much clearer: class Array does Array of Str | Array of Int | ... { ... } I'm not saying that this is easy to implement, but I'd appreciate if it were part of Perl6 for a comprehensive set of types. I would also expect some work on the side of new classes/types to participate in this rw Array scheme. -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
[EMAIL PROTECTED] wrote: Er, isn't that not just the wrong way around? The point is to do the bookkeeping that an object is needed that does .meth() and that it is stored in $a, and to complain when that is not the case when it should be. The earlier the better. I don't understand why writing 'my X $a' needs at least a declaration of X, but then '$a.meth()' does not consider '.meth' as a bare method that needs a declaration in X? Because you can do sub infect(X $a is rw) { role bla { method meth() {...} } $a does bla; } my X $a; infect($a); a.meth(); Remember, you can even change the class of instanced objects using 'does' (or 'but', but it'll at least copy the object). And as the example above shows, this is statically intractable - it can happen in a sub in a different autoloaded module. Also, what do you want to do if you actually want $a.meth() to throw a catchable exception if $a doesn't implement meth? It's what many OO languages do. In fact, I can't recall a single OO language that isn't derived from C++ that does /not/ just throw a runtime exception on unknown method. Miro
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Miroslav Silovic wrote: Remember, you can even change the class of instanced objects using 'does' (or 'but', but it'll at least copy the object). And as the example above shows, this is statically intractable - it can happen in a sub in a different autoloaded module. Sorry this is a well established fact in this thread. If unspecificity is what you want than you use 'my $a;' and the compiler happily parses '$a.meth()' purely syntactically and generates code for dynamic lookup and potential exception throwing. Aaron's and my point is the reverse: what do we gain if the same applies when we kindly announce that $a should do X'ish things only. That of course includes late bound fancy versions of methods from the interface of X. If there's no difference why bother to make declarations? This whole thread is about semantics close to syntax. I mean we know that everything with a dot is a method which syntactically makes dot the infix method sigil or some such. But I want the compiler to do a bit more than just extracting the string after the dot from my source code and stash it in some namespace when I requested the constraint X. Is typing optional in the sense that it is no syntax error but otherwise ignored? To me this is pain but no gain :( BTW, is 'my ::X $a;' introducing X as unspecific as it could be? Just occupying the syntactic slot of a type? That could be usefull to start in an explorational style and eventually use the PTE (P(arrot|erl6) Type Engine) to infer what X should look like. I really see the PTE as the twin of the PGE---and no Perl hacker disavows the power of regular expressions and parsers ;) Also, what do you want to do if you actually want $a.meth() to throw a catchable exception if $a doesn't implement meth? It's what many OO languages do. In fact, I can't recall a single OO language that isn't derived from C++ that does /not/ just throw a runtime exception on unknown method. Well that would just be role X { method meth() {...} } by virtue of the nada operator---whatever exception it throws and how much it tells about X::meth(). -- TSa (Thomas Sandlaß)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Thu, Mar 31, 2005 at 06:35:06PM +0200, Thomas Sandlaß wrote: : Is typing optional in the sense that it is no syntax error but : otherwise ignored? To me this is pain but no gain :( Well, you guys keep ignoring the answer. Let me put it a bit more mathematically. The information in my X $a; is *necessary* but not *sufficient* to do method existence testing in standard Perl 6 at compile time. You can do it IFF you have the class information AND the classes are willing to cooperate in your scheme. In the current design, you can pragmatically request that all classes cooperate, and you will get the cooperation of all classes that haven't specifically been requested to be non-cooperative. This is what all the mumbo-jumbo about open/closed and final/non-final classes comes down to. One additional wrinkle is that *anyone* is allowed to declare a class non-cooperative (open or non-final) during *any* part of the compilation, so your method existence checking cannot be done at reduction time, but must be done as a separate pass from a CHECK block at the end of whatever lexical scope requested cooperation. CHECK blocks are construed to be the end of normal compilation; Perl 6 very much follows the Perl 5 model here. I hope this clears things up a little. Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Thu, 2005-03-31 at 11:51, Larry Wall wrote: my X $a; is *necessary* but not *sufficient* to do method existence testing in standard Perl 6 at compile time. You can do it IFF you have the class information AND the classes are willing to cooperate in your scheme. In the current design, you can pragmatically request that all classes cooperate, and you will get the cooperation of all classes that haven't specifically been requested to be non-cooperative. This is what all the mumbo-jumbo about open/closed and final/non-final classes comes down to. So let me try to unpeel that (I'm not trying to be difficult, it's just that this is a difficult topic as evidenced by the mountain of documentation on the topic by languages that try to be only HALF as flexible). If you declare a variable to be of a type (let's even say a class to be specific), then you have hinted to the compiler as to the nature of that variable, but nothing is certain. That is to say that the compiler cannot: * Make any type-massaging choices yet on (implicit or explicit) method invocations * Issue any errors based on signature miss-matches Ok? Now we move on to the idea of finalization. Please correct me where I conflate finalization and openness. I'm not sure I understand the difference at all (no, I'm certain I don't). We assert (don't have the docs handy, but I'll just arm-wave the syntax) that the class is now finalized. This means any attempt to re-define the interface of the class is a compile-time error, correct? What about changing the internals of the class (e.g. changing the code associated with a method without re-defining the signature)? Next, what are the conditions under which a class can be finalized? * Can we finalize a class which has non-finalized ancestors? * What if it has method parameters/return values or member variables whose types are not finalized? * What if it applies roles which are not finalized? Obviously each one of these questions comes with a host of what happens if questions given a yes answer Another question: how does finalization interact with a class's metaclass? Does the metaclass become a const? Is the type of a metaclass itself a finalized class? If not, can it be finalized by user code? One additional wrinkle is that *anyone* is allowed to declare a class non-cooperative (open or non-final) during *any* part of the compilation ... even after it is declared final? Will core types be finalized by default? I hope this clears things up a little. Clear that's a word ;-) Yes, your message helped. I can sense your exasperation, but it is my hope that asking stupid questions now means that we'll have smart answers by the time P6 is released. If I'm overly slowing the process, please say so, and I'll stop asking. -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Thu, 2005-03-31 at 13:11 -0500, Aaron Sherman wrote: I can't answer most of these well. However... One additional wrinkle is that *anyone* is allowed to declare a class non-cooperative (open or non-final) during *any* part of the compilation ... even after it is declared final? I hope so. Will core types be finalized by default? I hope not, but if so, I hope they include all of the behavior anyone could ever possibly want from them so that no one will ever have to decorate them to add that one little important missing feature. Open-Closed is a great idea until the most natural and easiest way to do something is to to redefine a little bit of the world. -- c
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
I'm no expert, but here's my take: On Thu, Mar 31, 2005 at 01:11:37PM -0500, Aaron Sherman wrote: If you declare a variable to be of a type (let's even say a class to be specific), then you have hinted to the compiler as to the nature of that variable, but nothing is certain. That is to say that the compiler cannot: * Make any type-massaging choices yet on (implicit or explicit) method invocations * Issue any errors based on signature miss-matches Ok? I don't quite know what you mean by type massaging choices, but sure the compiler *can* issue errors on signature mismatch. When you say my X $a; the compiler has to treat $a like an X even if it doesn't know everything there is to know about X (X may not even be defined yet). So if you pass $a to a routine that's expecting a Y, then the compiler can and will carp. If, by type massaging choices you mean deciding whether or not to accept a variable in a signature slot based on its type (i.e., if the parameter is declared as a super-type of X, do we accept a X for this parameter), then I think the compiler can do that as well. Now we move on to the idea of finalization. Please correct me where I conflate finalization and openness. I'm not sure I understand the difference at all (no, I'm certain I don't). final classes can not be derived from, non-final can. closed classes can not have new methods added to them later on, open classes can. We assert (don't have the docs handy, but I'll just arm-wave the syntax) that the class is now finalized. This means any attempt to re-define the interface of the class is a compile-time error, correct? What about changing the internals of the class (e.g. changing the code associated with a method without re-defining the signature)? If I assume you're talking about closed classes here (as it seems), then I'd say that you can not redefine the interface or change it's internals. If you really do mean finalized classes, then I'd think that you *can* change the interface or the internals. Next, what are the conditions under which a class can be finalized? * Can we finalize a class which has non-finalized ancestors? Certainly. Even if you meant can we close a class which has non-closed ancestors, I think you can do both. Not sure though. * What if it has method parameters/return values or member variables whose types are not finalized? Finalization and closing is not something you do to instances, but rather classes. * What if it applies roles which are not finalized? I don't think you can finalize roles (it doesn't make sense to me to be able to do so anyway) Closing roles, I think you can do though. Also, according to http://dev.perl.org/perl6/synopsis/S12.html#Open_vs_Closed_Classes There is no syntax for declaring individual classes closed or final. The application may only request that the optimizer close and finalize unmarked classes. So you would have a default policy of closed/final and then open/unfinalize individual classes, or have a default policy of open/non-final and have no way to close/finalize individual classes. Another question: how does finalization interact with a class's metaclass? I don't think it does, except that that may be the hook by which we obtain no dreviatives allowed on implementation. (i.e. the meta-classes enforces the restrictions placed upon the class) Does the metaclass become a const? Is the type of a metaclass itself a finalized class? If not, can it be finalized by user code? You've strayed beyond my idea-space here :-) One additional wrinkle is that *anyone* is allowed to declare a class non-cooperative (open or non-final) during *any* part of the compilation ... even after it is declared final? Sure. Will core types be finalized by default? No. It would be very un-perl-like to have such an unasked for restriction IMHO. Caveat lector, I'm not of the cabal. -Scott -- Jonathan Scott Duff [EMAIL PROTECTED]
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Thu, 2005-03-31 at 15:25, chromatic wrote: On Thu, 2005-03-31 at 13:11 -0500, Aaron Sherman wrote: I can't answer most of these well. However... Open-Closed is a great idea until the most natural and easiest way to do something is to to redefine a little bit of the world. You seemed to have answered my questions on the basis of a piece of information which I asked for, but you did not include... I took the liberty of re-reading S12 and A12 to find it, and got two answers which are almost the same. After having found the bit on open vs. final, I'm even more at a loss, but I have some answers... let me start trying to put them together for others to scrutinize (I'm not taking a pro or con position on any of this yet, just trying to get the details worked out). S12 sayeth: By default, all classes in Perl are non-final, which means you can derive from them. Ok, so this answers a few of my questions. Namely, you can't do anything particularly useful by finalizing your class (and A12 tells us you can't really anyway). You would have to finalize EVERYTHING in your class's inheritance chain up to, but not including it, and then close your own class in order to allow compile-time error detection and type massaging. Also note that A12 says: Likewise, a final class (to use the Java term) is one that you know will never be derived from, let alone mucked with internally. which subtly contradicts (or at least expands on in an unexpected way) S12 by implying that final implies closed does it? S12 then goes on to say: They are also open, which means you can add more methods to them, though you have to be explicit that that is what you're doing: This is far too limited, isn't it? What can we normally do to a class? In conversations here, we've previously arm-waved that we'd be able to do damn near anything we pleased through the metaclass... but perhaps that's not true? I think that's pretty much what I know and don't know as of now... anyone want to take a shot? -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Luke Palmer wrote: Unless the caller can't see the signature, as is the case with methods. [..] Again, this can't be done unless you know the signature. And in fact, we can't do type inference on methods unless we do type inference everywhere, which we can't do if we want an autoloader. This sounds to me even messier than the C header file mishap, or even the old KR days without protoyped declarations! How can the programmer know about the signature of a method? I guess from some documentation. And the prime documentation of an interface is a formal interface definition provided by the language. This is e.g. what Ada does. Also CORBA is build around its IDL (Interface Definition Language) and from version 3.0 onwards a CDL (Component Definition Language). If I understand you correctly the use statement is more like a linker/loader directive than a compile time interface include? BTW, is it foreseen to have a clear conceptual split between the compiler and the loader? Or is that all blurred? -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Tue, 2005-03-29 at 16:00 -0700, Luke Palmer wrote: Unless the caller can't see the signature, as is the case with methods. I need to understand this piece. In this code: class X { method meth() {...} } class Y is X { method meth() is rw(int $r) {...} } sub foo { return my Y $tmp } my X $a = foo(); $a.meth() = 8; What happens? Do we impose a compiler-level restriction on the call that prevents this, or do we always allow it, and let the run-time take care of it? My preference by far is to let the compiler tell you that it's illegal because there's no valid reason for a sub-class to change the semantics of a polymorphically invoked method like this. The sub-class might introduce new semantics, but when manipulated as a base-class those semantics should only come into play when they are invoked via the interface of the base class. That sounds like an almost axiomatic truism to me, but if I read what you wrote correctly, you don't seem to agree. It's important to look at this as a two(more?)-stage process with different agendas and limitations, no? More generally, I think it's always a valid thing for the compiler to impose the restrictions of the type it knows about, regardless of what polymorphism might discover later on at run-time. This means that you can't do this: class X { } class Y { method m (int $a) {...} } my X $ob = get_me_a_Y(); $ob.m(1); because X does not provide an m. Again, this can't be done unless you know the signature. And in fact, we can't do type inference on methods unless we do type inference everywhere, which we can't do if we want an autoloader. You can combine and autoloader with type inference. You may not choose to, but it's not impossible. You can load the signatures ahead of time, and link the code at run-time. What gets dicy is this: eval use X; my X $a; $a.m(1); I think that's invalid too, but I'm not sure.
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Aaron Sherman writes: On Tue, 2005-03-29 at 16:00 -0700, Luke Palmer wrote: Unless the caller can't see the signature, as is the case with methods. I need to understand this piece. In this code: class X { method meth() {...} } class Y is X { method meth() is rw(int $r) {...} } sub foo { return my Y $tmp } my X $a = foo(); $a.meth() = 8; What happens? Do we impose a compiler-level restriction on the call that prevents this, or do we always allow it, and let the run-time take care of it? My preference by far is to let the compiler tell you that it's illegal because there's no valid reason for a sub-class to change the semantics of a polymorphically invoked method like this. The sub-class might introduce new semantics, but when manipulated as a base-class those semantics should only come into play when they are invoked via the interface of the base class. That sounds like an almost axiomatic truism to me, but if I read what you wrote correctly, you don't seem to agree. No, I think I agree with you here. But what happens if you change you're second-to-last line to: my $a = foo(); $a.meth() = 8; Perl 6 is both a statically typed language and a dynamically typed language, and the problems that I am addressing are mostly about the dynamic part. You can combine and autoloader with type inference. You may not choose to, but it's not impossible. You can load the signatures ahead of time, and link the code at run-time. What gets dicy is this: eval use X; my X $a; $a.m(1); I think that's invalid too, but I'm not sure. Again, that's invalid in the static world, but it should work if you s/my X/my/. The kinds of type inferrence people are saying would solve our problems require us to infer code like this, which we can't do. There _is_ a way to do it, actually, but we need to really screw around with what kinds of things are inferred. In the case: my $a; $a.m(1); We assign the type objects with an 'm' method that can take a single integer to $a. This is a category of objects that spans many classes, and does not fit into a nice little tree. I think that before we take on such an idea, we should look for research about this kind of type inference. Luke
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, Mar 30, 2005 at 09:40:26AM -0700, Luke Palmer wrote: : There _is_ a way to do it, actually, but we need to really screw around : with what kinds of things are inferred. In the case: : : my $a; : $a.m(1); : : We assign the type objects with an 'm' method that can take a single : integer to $a. This is a category of objects that spans many classes, : and does not fit into a nice little tree. I think it's perfectly fine for the compiler to make use of whatever information it has. The trick is to never make any unwarranted assumptions, such as Nobody will ever add another class with an 'm' method. It can assume that only if you explicitly tell it to, and if nobody has jimmied any classes to remain open and/or non-final. Otherwise you have to at least be prepared to recalculate the effective meaning of your 'm' type, and know when that recalculation is necessary. Even if classes are open and non-final, you can at least cache information that is temporarily true, and make good use of it. Perl 5 certainly takes that approach in spots. Perl 5 doesn't do a good job of localizing the damage, however. If you monkey around with your classes, it basically throws away all the cached data by incrementing a generation count. : I think that before we take on such an idea, we should look for : research about this kind of type inference. As long as we includes you, that's fine by me. :-) Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
HaloO Luke, you wrote: No, I think I agree with you here. But what happens if you change you're second-to-last line to: my $a = foo(); $a.meth() = 8; Perl 6 is both a statically typed language and a dynamically typed language, and the problems that I am addressing are mostly about the dynamic part. My state of affairs is that these two lines of code lack declarations that clearly announce what the user of foo and X wanted: 1) foo returns an X 2) an X does .meth() Where, how and if these are implemented, autoloaded or what not is another business. Client side type checking ensures that no usage outside the declared behaviour occurs. For larger declarations I which to put them into an interface module, package, header or however that is called and include it. On the implementation side we get the complementary definitions: 1) here's an X that does .meth() 2) here's a foo that returns an X The dynamism of Perl6 should revolve around how to bring these two sides of an interface together conveniently and efficiently. Just using 1% of a big package shouldn't let your 10-liner become a bloated pig! And of course the builtin functionality and the packages available from CPAN save the typical small scale programmer from extensive declarations. But to use a complex module you have to read documentation to get the idea to call .meth() in the first place. And then I like to get the hint from the compiler that there is no .mth() and happily correct the spelling error. Spotting these types of errors is were computers are much better than humans :) We assign the type objects with an 'm' method that can take a single integer to $a. This is a category of objects that spans many classes, and does not fit into a nice little tree. I think that before we take on such an idea, we should look for research about this kind of type inference. Type calculations are not inherently difficult, especially when junctive values are at hand. The problem is that the inference can quickly diverge to the useless something is done to an anything. Dwimmery works best when it bridges little gaps in an otherwise very rich semantic network. -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 11:40, Luke Palmer wrote: No, I think I agree with you here. But what happens if you change you're second-to-last line to: my $a = foo(); $a.meth() = 8; Perl 6 is both a statically typed language and a dynamically typed language, and the problems that I am addressing are mostly about the dynamic part. The way I've always thought about that one (and perhaps I'm just misguided) is that you're really saying: my unknown $a = foo(); $a.meth() = 8; And unknown does something strange (unique?) along the lines of: class unknown is scalar, pragma::everything {...} That is, logically, unknown allows you to use any interface (note that I said pragma because sub-classes of scalar don't get this behavior), but realistically, a compiler must simply throw up its hands on that ONE type of variable and allow you to get away with nearly anything (and leave it up to the run-time to use your vtable to discover the truth). The feature you get here is that a compiler that wanted to spend hours of compute-time validating your program COULD search every known interface, and tell you: Unknown method signature in dynamic call at line 100 or an even smarter compiler could say: Method signature on line 100 unrelated to previous usage on line 98 That is, you called a method on line 98 that matches no classes above, below or the same as the classes matched by the signature of the method you called on line 100. This kind of lint checking would be very handy, though I'm sure it would be too time-consuming for the general -w case. eval use X; my X $a; $a.m(1); I think that's invalid too, but I'm not sure. Again, that's invalid in the static world, but it should work if you s/my X/my/. The kinds of type inferrence people are saying would solve our problems require us to infer code like this, which we can't do. I think there, you are well justified in saying that you can try to get away with it, but a compiler that's smart enough to realize that you need a run-time loaded dynamic type to make it work should punt it. Of course, that ASSUMES that auto-loading is a two-stage process with an interface definition and a run-time code load. Given that, what you wanted was auto-loading, not run-time string eval. Those are not the same thing. If you're doing code-generation at run-time ... huh, what happens, let me think... Let's say you generate this code from a specification of some sort: class __c001 { method __m001(int $__i001) {...} } __c001.new; and then try to call: (eval $generated_code).__m001(1); Ok, that's good because eval returns the same unknown scalar type as a bare my declares. I guess you can also taint anything that comes from an eval and just avert your gaze... you'll have to taint objects that use non-Perl6 object systems in the same way, anyhoo: my $thing = Runtime::Python::re::compile('.*'); $thing.search('moo'); There _is_ a way to do it, actually, but we need to really screw around with what kinds of things are inferred. In the case: my $a; $a.m(1); We assign the type objects with an 'm' method that can take a single integer to $a. This is a category of objects that spans many classes, and does not fit into a nice little tree. I think that before we take on such an idea, we should look for research about this kind of type inference. Heh well, here's where we notice that Aaron reads and replies in series by paragraph ;-) -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Thomas Sandla writes: And of course the builtin functionality and the packages available from CPAN save the typical small scale programmer from extensive declarations. But to use a complex module you have to read documentation to get the idea to call .meth() in the first place. And then I like to get the hint from the compiler that there is no .mth() and happily correct the spelling error. Spotting these types of errors is were computers are much better than humans :) And it sure would be able to spot that kind of error, supposing the sub declaration is in scope. But suppose it weren't. Maybe that's a bit hard to fathom if you haven't written an autoloader. Suppose, then, that you have this code: class CodeProxy { has Code $.code is rw; sub call ($a) { $.code($a); } } This is valid Perl 6, and anyone who says otherwise (because of type signatures) is changing the Perl philosophy too much to be taken seriously. Now, tell me at compile time whether the call inside `call` is valid. Of course, the alleged type inferencer can do some magic and make sure that it is. It says that the $.code member variable is not just of type `Code`, but of type `Code is sig($x) forall $x` (are siglets still around?). Then this code would not fail to compile, but any code that tried to assign an incompatible routine to the .code member would fail to compile. At runtime, you load in a new subclass of `CodeProxy`, `DoubleCodeProxy` (this programmer apparently doesn't know that we support variadic signatures :-) class DoubleCodeProxy is CodeProxy { method call ($a, +$b) { .code().($a, $b); } } Again, undisputably valid Perl 6. Every method takes an implicit `*%`, so it's not an interface violation to add a new named parameter. And now it's okay to assign a code object to $.code which manditorily takes two parameters, if that object happens to be a `DoubleCodeProxy`. But we can't tell whether it's a `DoubleCodeProxy` by type inference, because we didn't even know what a `DoubleCodeProxy` was at compile time. C++ gets around this problem by disallowing a declaration like `has Code $.code` -- All declarations must be fully specified. Perl is not going to do that. Unless I've mis-argued somewhere (I've been straining to get this message done before my next class starts, so my thinking may be sloppy), this example case requires the check to be put off until runtime. In that case, you certainly can't use inferred type information to make any semantic choices, and the best we can do is to use it as a compile-time error checker (in the cases where it's capable of doing so) and as an optimizer. Luke
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Larry Wall wrote: I think it's perfectly fine for the compiler to make use of whatever information it has. The trick is to never make any unwarranted assumptions, such as Nobody will ever add another class with an 'm' method. Er, isn't that not just the wrong way around? The point is to do the bookkeeping that an object is needed that does .meth() and that it is stored in $a, and to complain when that is not the case when it should be. The earlier the better. I don't understand why writing 'my X $a' needs at least a declaration of X, but then '$a.meth()' does not consider '.meth' as a bare method that needs a declaration in X? Polymorphism is about requiring that objects do compare and then sort a bunch of them using that particular role---not more not less. Or think of US Postal just transporting letters irrespective of them containing Anthrax or not, as long as they bear the right stamps! -- TSa (Thomas Sandlaß)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 13:53, Luke Palmer wrote: class CodeProxy { has Code $.code is rw; sub call ($a) { $.code($a); } } This is valid Perl 6, and anyone who says otherwise (because of type signatures) is changing the Perl philosophy too much to be taken seriously. Now, tell me at compile time whether the call inside `call` is valid. It's valid because it's a function call on a code ref. In that case, the compiler has to hand your request off to the run-time to check the vtable of $.code. Clearly that's a special case. I may have missed context at the start, but are we worried about the special cases or the general case or the implications to the general case of the special cases? At runtime, you load in a new subclass of `CodeProxy`, `DoubleCodeProxy` (this programmer apparently doesn't know that we support variadic signatures :-) I think this is where you're stepping off the path I thought we were on, and I agree with the rest of your message FOR ONE CASE, but not all. Runtime loading can happen in many ways, but let's break them down into two camps: with and without a compile-time interface definition. In the first camp you have autoload. In the second camp you have low-level (e.g. Parrot) code that happens to have no interface definition (because it's pure PBC or because it came from another language) and evaluated strings. What I do not think should be allowed (and I may be contradicting Larry here, which I realize is taking my life in my hands ;) is violating the compile-time view of the static type tree. That is, you can load an object foo at run-time, without and interface definition, but it can't change the shape of the type tree or its existing interfaces. If it wants to do that, it has to provide an interface def (e.g. what an autoload module should be able to provide). Why? Because if you can do that, then this: my X $a; $a.m(1) = 1; ALWAYS has to work because you might have replaced X at run-time with a class that has a method m(int) is rw(), and the compiler must silently (perhaps with an optional warning) permit it. Please think carefully about how dynamic you want Perl 6 to be Dynamic is good, but there's such a thing as too much of a good thing. -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, Mar 30, 2005 at 12:05:12PM +0200, Thomas Sandlaß wrote: : If I understand you correctly the use statement is more like a : linker/loader directive than a compile time interface include? That is up to the module being used. use is a linker, but it's only required to link enough information into the caller such that the caller can see the interface. Loading can happen later--though it typically happens on first use rather than first use. The point is there's no separate linker step. Everything is demand driven, and what gets linked in at compile time depends on what gets demanded at compile time. If something isn't demanded till run time, the compiler can't know it, unless you tell it in advance somehow, which presumes that *you* know it. And maybe you don't. And that is when late binding is ever so much handier than early. : BTW, is it foreseen to have a clear conceptual split between the : compiler and the loader? Or is that all blurred? Clear conceptual splits often hide false dichotomies. The split is rather blurry for Perl 5, and Perl 6 will only continue the trend. There are good uses for both early binding and late binding, and for various forms of binding in between--it's a continuum, and each module is allowed to draw the boundary wherever and however it likes. Birds naturally prefer early binding to late binding; worms will naturally disagree. Rolling stones gather no type constraints. Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 14:29 -0500, Aaron Sherman wrote: What I do not think should be allowed (and I may be contradicting Larry here, which I realize is taking my life in my hands ;) is violating the compile-time view of the static type tree. That is, you can load an object foo at run-time, without and interface definition, but it can't change the shape of the type tree or its existing interfaces. If it wants to do that, it has to provide an interface def (e.g. what an autoload module should be able to provide). I disagree, *unless* you predeclare that you don't plan to change anything -- as an optimization hint. (Though if you write a module to do this as a policy, I won't hunt you down with my +2 club of Optimize for the Programmer, not the Compiler.) I certainly plan to continue to instrument code at runtime (and not just really slushy, partially slushy, and permafrost compile time). -- c
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 14:57, chromatic wrote: I certainly plan to continue to instrument code at runtime (and not just really slushy, partially slushy, and permafrost compile time). That's FINE, and no one should stop you! What I was referring to was only the items that an interface definition would be concerned with (that is, those things which would invalidate the compiler's assumptions). An example follows. Original code: class X { method m(int $i) { say Hello, world } } Valid string to eval: q{class X { method m(int $i) { die Goodbye, world } }} Invalid string to eval: q{class X { method m(int $i) is rw($string) { say $string } }} The latter changes the interface definition, and thus invalidates the compiler's assumptions, but you can instrument the code all you like, re-defining any darned thing you wish! If you allow the interface definition to change, you're not optimizing for the programmer. You're optimizing for the amount of time you spend in the debugger. Failing to eval early because code would have changed the interface (or type hierarchy) of your types will save thousands of programmers everywhere much debugging time. Like I said, if you allow run-time munging of the type interfaces, then you can't tell if this is valid or invalid: my X $a; $a.m(1); you have to allow it always, regardless of the definition of X. In fact, you can NEVER reject ANY method or function invocation based on signature, since it might change at run-time. Is that really what you want? -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 15:27 -0500, Aaron Sherman wrote: Like I said, if you allow run-time munging of the type interfaces, then you can't tell if this is valid or invalid: my X $a; $a.m(1); you have to allow it always, regardless of the definition of X. In fact, you can NEVER reject ANY method or function invocation based on signature, since it might change at run-time. Is that really what you want? I want the possibility to correct bad decisions of interfaces and signatures whenever possible in the most minimally intrusive way possible. I don't want to work around a module or class or function or method where someone tried to be helpful by saying Oh, this will absolutely never change, ever and the compiler helpfully froze that decision forever. Sometimes that means changing it outside the incorrect code. I don't trust any compiler to make every decision correctly, and in cases of ambiguity I believe that I can give it better hints than it can reason for itself if I need the extra speed or safely. A compiler that assumes incorrectly and disallows programmers to do useful things because its holds those assumptions as precious is wrong -- especially in cases where even the programmer can't tell if code is valid or invalid until the program actually runs. -- c
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Luke Palmer wrote: class CodeProxy { has Code $.code is rw; sub call ($a) { $.code($a); } } This is valid Perl 6, Hmm, a sub in a class? I guess that should be a method. OTOH a class is just a funny module, so might be OK. But that is the syntax realm. and anyone who says otherwise (because of type signatures) is changing the Perl philosophy too much to be taken seriously. Now, tell me at compile time whether the call inside `call` is valid. Ups, before we start talking past each other: I think a type system is just a tool that reminds you to your declarations. No declarations, no reminder, it's that simple. I would like the typing of $.code as Code to be necessary to apply the .() invocation operator on it. The rest is deferred to runtime if that is what you want. And I'm completly unsure how much parrot and/or perl revert back into compile state when you bring in new source code at runtime. Or how much load time activity is needed for a byte code file. The question if instances of DoubleCodeProxy are subtypes of instances of CodeProxy boils down to the question if ($) : ($, +$) with : beeing the subtype relation. Is that the right siglet syntax? Since named-only parameters are optional the relation holds. This subtype relation allows: my CodeProxy $cp = DoubleCodeProxy.new; # needs DoubleCodeProxy : CodeProxy $cp.code = sub ($x, +$y = unknown) { say x = $x, y = $y }; $cp.call( first, b = second ); # prints x = first, y = second $cp.call( one ); # prints x = one, y = unknown $t = $cp.code; $cp.code = sub () { say void }; # no problem, type is Code $cp.call( X ); # gives runtime error on closure in $.code $cp.code = $t; $cp.call(); # compile error: too few args $cp.call( 1, 2 ); # compile error: too many positional args $cp.blahh( 23 ); # compile error/warning: no such method declared method CodeProxy::blubber(: $z ) { ... } $cp.blubber( 42 ); # could die on ... at runtime if no .blubber autoloaded $cp.call( 1|2|3 ); # autothreads??? I leave that to Damian :) -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
chromatic wrote: A compiler that assumes incorrectly and disallows programmers to do useful things because its holds those assumptions as precious is wrong -- especially in cases where even the programmer can't tell if code is valid or invalid until the program actually runs. Me neither. One should think of a type system like dependency declarations in a Makefile: you get out what you put in. Too few dependencies might result in incomplete rebuilds. Complete dependencies might remind you how convoluted your design is. And make doesn't manage circular dependencies :) -- TSa (Thomas Sandlaß)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Aaron Sherman wrote: No, that was most of the point. foo did not declare a return type, and while my code was simplistic, we obviously cannot be certain what foo might return in the general case. Sorry that I've spoiled that. But I wonder if it's just in the examples here on the list or a general laxity to not specify a return type of subs and methods. I consider leaving it to the compiler to infer it bad style. BTW, what is the default return type? Just Void? Is an explicit return statement than a compile error? -- TSa (Thomas Sandlaß)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Thomas Sandla writes: Aaron Sherman wrote: No, that was most of the point. foo did not declare a return type, and while my code was simplistic, we obviously cannot be certain what foo might return in the general case. Sorry that I've spoiled that. But I wonder if it's just in the examples here on the list or a general laxity to not specify a return type of subs and methods. It depends on the programmer. I'm sure that you and probably Aaron will always declare your return types. I'm quite sure that I will not except for when it effects a semantic that I want. Ultimately, it depends on how Perl 5-ish you want to program Perl 6 in this regard. I definitely enjoy Perl 5's late binding for the most part. Again, I usually only resort to early binding things (like type declarations and sub prototypes) when it changes the semantics in some way. Luke
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Thomas Sandla writes: Luke Palmer wrote: class CodeProxy { has Code $.code is rw; sub call ($a) { $.code($a); } } This is valid Perl 6, Hmm, a sub in a class? I guess that should be a method. OTOH a class is just a funny module, so might be OK. But that is the syntax realm. Hey, no pointing out errors when I'm arguing! :-) Yes, given a s/sub/method/ it is valid Perl 6. ;-). As for the rest of this message, see my coming reply to Aaron's message, which points out that we're beginning to talk past each other because the original context has been lost. Luke and anyone who says otherwise (because of type signatures) is changing the Perl philosophy too much to be taken seriously. Now, tell me at compile time whether the call inside `call` is valid. Ups, before we start talking past each other: I think a type system is just a tool that reminds you to your declarations. No declarations, no reminder, it's that simple. I would like the typing of $.code as Code to be necessary to apply the .() invocation operator on it. The rest is deferred to runtime if that is what you want. And I'm completly unsure how much parrot and/or perl revert back into compile state when you bring in new source code at runtime. Or how much load time activity is needed for a byte code file. The question if instances of DoubleCodeProxy are subtypes of instances of CodeProxy boils down to the question if ($) : ($, +$) with : beeing the subtype relation. Is that the right siglet syntax? Since named-only parameters are optional the relation holds. This subtype relation allows: my CodeProxy $cp = DoubleCodeProxy.new; # needs DoubleCodeProxy : CodeProxy $cp.code = sub ($x, +$y = unknown) { say x = $x, y = $y }; $cp.call( first, b = second ); # prints x = first, y = second $cp.call( one ); # prints x = one, y = unknown $t = $cp.code; $cp.code = sub () { say void }; # no problem, type is Code $cp.call( X ); # gives runtime error on closure in $.code $cp.code = $t; $cp.call(); # compile error: too few args $cp.call( 1, 2 ); # compile error: too many positional args $cp.blahh( 23 ); # compile error/warning: no such method declared method CodeProxy::blubber(: $z ) { ... } $cp.blubber( 42 ); # could die on ... at runtime if no .blubber autoloaded $cp.call( 1|2|3 ); # autothreads??? I leave that to Damian :) -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Aaron Sherman writes: What I do not think should be allowed (and I may be contradicting Larry here, which I realize is taking my life in my hands ;) is violating the compile-time view of the static type tree. That sentence is getting pretty C++-derived-like, which Perl is hardly anymore. We have to reorganize your brain a bit. Let's pretend that we're in Smalltalk instead of Java (no offense or compliment to either--I'm just taking extremes). Types don't form a tree. /Classes/ form a dag, which is, for all intents and purposes, a tree. But types are something very different. There are three kinds of types: * Roles (types with behavior) * Subtypes (roles with value restriction) * Classes (roles with an implementation specification) In particular, subtypes can form very complex non-tree-like structures, and structures which are not determinable by the compiler in the general case (if they were, then we'd have Gdel's truth machine). But that's okay, because it all boils down to calling the subtype closures and having those determine the implications of the structure, bypassing the structure itself. Let's step back into Perl 5 for a moment and pretend that objects are just blessed hashes again. If every object has some metadata stuffed into that hash, then you could really factor all three of these types of types into the subtype category. Subtypes are something that you can't really do any static analysis on. That means that I can circumvent your static view rule by doing exactly that: putting metadata on objects and making every type a subtype. But because the compiler has every ability to do that for us, and might just be the way it does things, it seems like we've just run in a big circle: outlawing something possible, and then walking through a loophole to make it possible again. That is, you can load an object foo at run-time, without and interface definition, but it can't change the shape of the type tree or its existing interfaces. If it wants to do that, it has to provide an interface def (e.g. what an autoload module should be able to provide). Why? Because if you can do that, then this: my X $a; $a.m(1) = 1; ALWAYS has to work because you might have replaced X at run-time with a class that has a method m(int) is rw(), and the compiler must silently (perhaps with an optional warning) permit it. And if X were defined as `Any where { $_.can('m') }`, then could you still make that guarantee? You could say no, we can't so that would be an illegal code segment at compile time, then I ask that you consider if X were defined as `Any where { $_.can('m') $_.CLASS.m ~~ rw }` (testing whether it has an rw m method... barring syntax). You'd have to say no there, too, because there's no way to tell what that opaque codeblock is doing. Please think carefully about how dynamic you want Perl 6 to be Dynamic is good, but there's such a thing as too much of a good thing. We'd like Perl 6 to be as dynamic as Perl 5. Luke
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Aaron Sherman writes: On Wed, 2005-03-30 at 13:53, Luke Palmer wrote: class CodeProxy { has Code $.code is rw; sub call ($a) { $.code($a); } } This is valid Perl 6, and anyone who says otherwise (because of type signatures) is changing the Perl philosophy too much to be taken seriously. Now, tell me at compile time whether the call inside `call` is valid. It's valid because it's a function call on a code ref. In that case, the compiler has to hand your request off to the run-time to check the vtable of $.code. Clearly that's a special case. I may have missed context at the start, but are we worried about the special cases or the general case or the implications to the general case of the special cases? Okay, now we're starting to talk past each other. I /think/ Thomas orignially suggested that we use type inference to determine whether to lvalue cast an argument or not, which is what I got all worked up about. I'm saying that you can't determine that kind of thing in general at compile time. I'm all for an optional strong type system, as long as it remains optional and mixable (so static things and dynamic things can play nicely together, whether the module is static and the user dynamic or vice-versa). Luke
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Aaron Sherman writes: Please think carefully about how dynamic you want Perl 6 to be Dynamic is good, but there's such a thing as too much of a good thing. We'd like Perl 6 to be as dynamic as Perl 5. We'd think that is impossible. Perl 5 had full control of the run-time, Perl 6 does not. Like hell it doesn't. Parrot is designed to support Perl 5. Perl 6 can do all the fancy stuff that Perl 5 did. If the Perl 6 compiler runs in Parrot, then it can control Parrot as it compiles, and reap information from that as it compiles. Parrot can easily redefine stuff on the fly and eval code at runtime. I don't see what full control of the run-time Perl 5 has that Perl 6 won't (if you have something specific in mind, enlighten me please). What's more, Perl 6 introduces types, mmd, function signature overloading, operator overloading and a host of other features which, combined with the level of dynamism found in Perl 5 would seem to me to lead to a compiler which cannot assist the user in writing debuggable code. You keep mentioning this thing debuggable code and saying that adding dynamism impairs it. I'd say that Perl 5 is debuggable; I can certainly debug it. The kinds of modules that I work on introduce types and mmd, where Perl 5 already had operator overloading. I don't understand how adding dyanmism impairs debuggability[1]. The reason that types and MMD can be introduced into Perl 5 is because it's so dynamic. We, as language designers in 2005, can't possibly know what will be to us as MMD is to perl 5, but we want module writers to be able to implement it, whatever it is. Sorry I'm getting so worked up here It's just that in designing the next generation of a language that I cherish for its dynamism and freedom, I don't like the idea of restricting that in the interest of... whatever the interest is in (I can't actually tell with this argument). I think what Perl 6 can offer us over Perl 5 in terms of safety, on a very feature-removed level, is much more comprehensive compile information available to the program. We could easily leave out the static type system from Perl 6 (not that I actually want to do this), and a module that implements it would be a heck of a lot easier to write than a module that implements it in Perl 5. Perl 6 gives you so many levels of control: lexical syntax control, hooks for everything you can dream of, possibility of generating pure parrot code inline, continuations (which help in writing a debugger), that I can't fathom how this could less debuggable than Perl 5. If you want to see when something, anything at all, is happening, stick a debugger hook in there. The more static we make our language--the less dynamic we allow it to be--the more debugging power we're taking away from the programmer. The lose of making things dynamic is that the compiler can't make as many assumptions, but Perl 6 allows many ways to tell it when it can make assumptions. As chromatic said, the programmer usually knows when the compiler can make assumptions better than the compiler does anyway. Whew... Okay, how can I turn around my rant and make it say something productive? I probably can't tonight. Nice yelling at you. :-) Luke [1] It might in a traditional debugger, but we are free to write our debugger in the extremely dynamic Perl 6, running it right alongside our program with all of our introspection needs at hand. If our debugger isn't good enough, we have the tools to write a better one. And for people like me who don't use the perl debugger, but who prefer print statements and Data::Dumper diagnostics, more dynamism implies more debugging power, not less.
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
According to Luke Palmer: [Perl 5] had to construct lvalues out of all arguments (for which that made sense) because the sub might modify them. No, actually, that wasn't the reason. Perl 5 passes all values by implicit mutable reference because it's faster, not because it's better. I suspect Larry might have passed arguments by read-only reference in Perl 5 as well, had he found a way to make it fast. -- Chip Salzenberg- a.k.a. -[EMAIL PROTECTED] Open Source is not an excuse to write fun code then leave the actual work to others.
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Luke Palmer wrote: Okay, now we're starting to talk past each other. I /think/ Thomas orignially suggested that we use type inference to determine whether to lvalue cast an argument or not, which is what I got all worked up about. Actually I was returning to the subject of co- or contravariance of parametric types but trying to avoid these terms. I gave an example how to get a Str into an Array of Int when you assume in general that Array of Int : Array of Any. Which is reasonable only for reading because the reader doesn't care of the type and Int is compatible with such a reading. For writing you need the reverse relation because the writer expects an array that accepts Ints and and Array of Any does this. For a read-write Array both cases must hold, thus only type equality is sound. So when the compiler knows about a 'is rw' trait on a parameter and the type of an array---and it does so the latest when the call is attempted, but that is not the compiler then---it should reject the call! I'm saying that you can't determine that kind of thing in general at compile time. Of course not, but the question is than just shifted to: do you want a runtime exception when sub foo( @a is rw ) is called with an Array of Int? If you answer no, than you take the consequence that this Array of Int might contain other things than Ints. That's all. There is no type inference per se in my argument. It just might help the compiler to gather the necessary type information to ask the above question at compile time. Larry takes the point of view that the Str goes in but the Array knows that it should be an Int and nicely converts that for you. And actually Any might just be a glb (greatest upper bound) of Int and Str, written Int|Str in Perl6, so the type checker knows that *this* case is OK. But it will complain if Any isn't a glb of SomeOtherType and you call foo with Array of SomeOtherType. Note that Int|Str : Str Str : Int|Str Int|Str : Int Int : Int|Str holds. Given an even more complex Any type that encompasses the general purpose types of Perl6---namely Str, Int, Num, Bool and Refs thereof--- the lazy Perl6 programmer gets what Perl5 did all the time. This is what is called Render the Illusion of Simplicity. This illusion fades when you get the compile time warning no glb for Any and SomeOtherType and you have to go figure what to do about it ;) But once again these might hit a strong programmer and the not so strong ones a kept in the illusion: look I just use SomeOtherType and it works. I'm all for an optional strong type system, as long as it remains optional and mixable (so static things and dynamic things can play nicely together, whether the module is static and the user dynamic or vice-versa). Optional in what sense? -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 17:09, Luke Palmer wrote: Aaron Sherman writes: What I do not think should be allowed (and I may be contradicting Larry here, which I realize is taking my life in my hands ;) is violating the compile-time view of the static type tree. That sentence is getting pretty C++-derived-like, I think you mis-read what I wrote, and it was in a context that flowed from previous messages. I was referring to the part of the type tree (multi-root, directed, acyclical graph) which I had deemed to be static for the sake of handling interfaces sanely at compile-time. Hence the scary-quotes on static, as we were not in agreement on that point. Please think carefully about how dynamic you want Perl 6 to be Dynamic is good, but there's such a thing as too much of a good thing. We'd like Perl 6 to be as dynamic as Perl 5. We'd think that is impossible. Perl 5 had full control of the run-time, Perl 6 does not. Even Ponie cannot truly be as dynamic as vanilla Perl 5. What's more, Perl 6 introduces types, mmd, function signature overloading, operator overloading and a host of other features which, combined with the level of dynamism found in Perl 5 would seem to me to lead to a compiler which cannot assist the user in writing debuggable code. I like Perl 5, but Perl 6 is not Perl 5... we have to be willing to accept that there are trade-offs for the features we've added. One possible trade-off is increased difficulty in debugging code. One possible trade-off is slightly less dynamic code. Your other message: On Wed, 2005-03-30 at 17:15, Luke Palmer wrote: aron Sherman writes: It's valid because it's a function call on a code ref. In that case, the compiler has to hand your request off to the run-time to check the vtable of $.code. Clearly that's a special case. I may have missed context at the start, but are we worried about the special cases or the general case or the implications to the general case of the special cases? Okay, now we're starting to talk past each other. I /think/ Thomas orignially suggested that we use type inference to determine whether to lvalue cast an argument or not, which is what I got all worked up about. I'm saying that you can't determine that kind of thing in general at compile time. I'm all for an optional strong type system, as long as it remains optional and mixable (so static things and dynamic things can play nicely together, whether the module is static and the user dynamic or vice-versa). Ok, so let me start from that point and ask a question: When the Perl 6 compiler sees: my X $a; $a.m(1); What should it do? Options: * Accept the method call regardless of the definition of X * Accept the method call if it matches the signature from X * Accept the method call if {magic($*INTERP)} Not to be pushy or anything, but please pick one and if it's the last, we can start to have a conversation about what that line-noise at the end actually does. ;-) -- Aaron Sherman [EMAIL PROTECTED] Senior Systems Engineer and Toolsmith It's the sound of a satellite saying, 'get me down!' -Shriekback
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Wed, 2005-03-30 at 18:35 -0500, Aaron Sherman wrote: When the Perl 6 compiler sees: my X $a; $a.m(1); What should it do? Options: * Accept the method call regardless of the definition of X * Accept the method call if it matches the signature from X * Accept the method call if {magic($*INTERP)} That's a fair question, but I think you're leaving out several important pieces of information: * Where does $a come from? (As far as I see, it's just an uninteresting undef here, but I don't know if that's the point of the code.) * At what point in the program are you asking what the compiler sees? * Where's the definition of X in relation to this code? * What pragmas are in effect here? * What other code may have altered the type definition of X or undef? I don't think anyone can answer your question well without assuming some answers to my questions. -- c
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Luke Palmer wrote: So if you want things modified, you'd have to pass in a reference. Arrays and hashes would not generally have this restriction, since we pass references of those guys anyway. But I would really like to see a declaration of any possible modification in the interface of a sub. Otherwise you might find quite surprising things in your array, or terribly miss things. So after calling a sub that takes an array parameter the array argument should be in exactly the same state as before the call! And any attempt to use modifying operations in the sub should result in a compile time error. This is good for the optimizer as well. I don't see the above as a restriction. There are easy ways to achieve modifyable values by 'is copy' for temporary modifications in the sub and 'is rw' and 'is ref' for full access. But the caller clearly sees that in the signature. And the typechecker might throw exceptions when type safety can't be maintained through the sub call: sub foo (@a is rw) { @a[7] = heaven } # type of is Str my Int @i; foo( @i ); # type error/warning foo( @i as Array of Any ); # programmer takes responsibility foo( [EMAIL PROTECTED] ); # I'm not sure about that, but could be short of the above -- TSa (Thomas Sandla)
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Thomas Sandla writes: Luke Palmer wrote: So if you want things modified, you'd have to pass in a reference. Arrays and hashes would not generally have this restriction, since we pass references of those guys anyway. But I would really like to see a declaration of any possible modification in the interface of a sub. Of course. We already have this. Otherwise you might find quite surprising things in your array, or terribly miss things. So after calling a sub that takes an array parameter the array argument should be in exactly the same state as before the call! And any attempt to use modifying operations in the sub should result in a compile time error. This is good for the optimizer as well. I don't see the above as a restriction. There are easy ways to achieve modifyable values by 'is copy' for temporary modifications in the sub and 'is rw' and 'is ref' for full access. But the caller clearly sees that in the signature. Unless the caller can't see the signature, as is the case with methods. That's the point of my thinking. Perl 5 had a performance (and a slight semantic) problem with this. It had to construct lvalues out of all arguments (for which that made sense) because the sub might modify them. We'll still have to do that unless the rw-ness is marked somehow on the caller's side. And the typechecker might throw exceptions when type safety can't be maintained through the sub call: sub foo (@a is rw) { @a[7] = heaven } # type of is Str my Int @i; foo( @i ); # type error/warning Again, this can't be done unless you know the signature. And in fact, we can't do type inference on methods unless we do type inference everywhere, which we can't do if we want an autoloader. Luke
Parameter and trait questions - just how 'only' _is_ 'read-only'?
I'm working on enhancing Perl6::Subs[*] to support more parameter traits than just Cis required. I have some questions about parameters and traits. (These questions all apply to pure Perl 6, which I know I won't be able to translate completely, but I want to know which target I'm missing.) * Given a parameter CArray @a, it's obvious I'm not allowed to Cpush @a,1, because I didn't say Cis rw. But am I allowed to C@a[0]++? How about C@a[0][0]++? How deep is read-only-ness? * Similarly, how deep is the copy implied by Cis copy? * Do traits attach syntactically to the variable name, or to the declaration as a whole? variable: @a is rw of Array Array @a is rw declaration: @a of Array is rw Array @a is rw * As far as I can tell, the choice of spelling an array parameter CArray @a or CArray $a is entirely cosmetic: both @a and $a are capable of holding an Array reference. Is there actually a difference, e.g. in how they handle an undefined value? [*] Shameless Plug: Perl6::Subs is a source filter that lets you use much of the Perl 6 parameter syntax in your Perl 5 programs; and it enforces many constraints for you. You can even add your own constraints with Cwhere BLOCK subtyping. Amaze your enemies! Confound your friends! Use Perl6::Subs today! -- Chip Salzenberg- a.k.a. -[EMAIL PROTECTED] Open Source is not an excuse to write fun code then leave the actual work to others.
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Chip Salzenberg writes: I'm working on enhancing Perl6::Subs[*] to support more parameter traits than just Cis required. I have some questions about parameters and traits. (These questions all apply to pure Perl 6, which I know I won't be able to translate completely, but I want to know which target I'm missing.) * Given a parameter CArray @a, it's obvious I'm not allowed to Cpush @a,1, because I didn't say Cis rw. But am I allowed to C@a[0]++? How about C@a[0][0]++? How deep is read-only-ness? I believe that the default constant parameters is so we don't have to construct lvalues out of our arguments when we call. So that probably means that it's very shallow. On the language level, I've been thinking that it would be good to go C's way and not allow any parameter modification whatsoever. The problem is that in the presence of methods, we can't tell whether we have to lvaluize anymore, so we're back to the Perl 5 trap of lvaluizing everything. So if you want things modified, you'd have to pass in a reference. Arrays and hashes would not generally have this restriction, since we pass references of those guys anyway. * Similarly, how deep is the copy implied by Cis copy? I think it's exactly as deep as read-only-ness. * Do traits attach syntactically to the variable name, or to the declaration as a whole? variable: @a is rw of Array Array @a is rw declaration: @a of Array is rw Array @a is rw Well, from this example it seems like `of` should be tighter than `is`. * As far as I can tell, the choice of spelling an array parameter CArray @a or CArray $a is entirely cosmetic: both @a and $a are capable of holding an Array reference. Is there actually a difference, e.g. in how they handle an undefined value? Hmmm... well I think all scalars are allowed to be undef. Arrays aren't. So yeah, if you give @a undef, it probably gives you [] (or croaks, but I don't think that's a good idea). If you give $a undef, it gives you undef. [*] Shameless Plug: Perl6::Subs is a source filter that lets you use much of the Perl 6 parameter syntax in your Perl 5 programs; and it enforces many constraints for you. You can even add your own constraints with Cwhere BLOCK subtyping. Amaze your enemies! Confound your friends! Use Perl6::Subs today! Cool. Luke
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
Chip Salzenberg wrote: * As far as I can tell, the choice of spelling an array parameter CArray @a or CArray $a is entirely cosmetic: both @a and $a are capable of holding an Array reference. Is there actually a difference, e.g. in how they handle an undefined value? Uhm... It was my impression that one of those creates an Array of Arrays, and the other just an Array. In other words, using @ instead of $ puts a Array of in front of the supplied type. This makes sense when one considers orthogonality with CInt @a and CInt $a. But it's easy to get tripped up it. -- Rod Adams (Who needs more days in the week, so he can continue work on S29).
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
According to Rod Adams: Chip Salzenberg wrote: * As far as I can tell, the choice of spelling an array parameter CArray @a or CArray $a is entirely cosmetic: both @a and $a are capable of holding an Array reference. Is there actually a difference, e.g. in how they handle an undefined value? Uhm... It was my impression that one of those creates an Array of Arrays, and the other just an Array. Ah, my question had a bug. What I meant was: * As far as I can tell, the choice of spelling an array parameter C@a or CArray $a is entirely cosmetic: both @a and $a are capable of holding an Array reference. Is there actually a difference, e.g. in how they handle an undefined value? -- Chip Salzenberg- a.k.a. -[EMAIL PROTECTED] Open Source is not an excuse to write fun code then leave the actual work to others.
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Sat, Mar 26, 2005 at 03:45:30PM -0500, Chip Salzenberg wrote: : According to Rod Adams: : Chip Salzenberg wrote: : * As far as I can tell, the choice of spelling an array parameter :CArray @a or CArray $a is entirely cosmetic: both @a and :$a are capable of holding an Array reference. Is there actually :a difference, e.g. in how they handle an undefined value? : : Uhm... It was my impression that one of those creates an Array of : Arrays, and the other just an Array. : : Ah, my question had a bug. What I meant was: : : * As far as I can tell, the choice of spelling an array parameter :C@a or CArray $a is entirely cosmetic: both @a and $a are :capable of holding an Array reference. Is there actually a :difference, e.g. in how they handle an undefined value? Not really. The main difference is that @a will flatten in a list context, and $a won't. That being said, in Perl 5, if you say @a = undef; you don't get an undefined array. I'd like to make undef smart enough about list contexts that @a actually does end up undefined in Perl 6. That is, in scalar context, undef is a scalar value as in Perl 5, but in Perl 6, undef in list context means there isn't anything here if you try to look for it, so it's more like () in Perl 5, except that it also undefines the array if it's the only thing in the array. I don't know if that's an entirely consistent semantics, but I'd rather have a little inconsistency and preserve error informaiton for later debugging whenever possible, and that undef you tried to initialize the array with might have some interesting commentary in it. (Though, of course, my example above is a rather boring value of undef.) Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Sat, Mar 26, 2005 at 03:13:07AM -0700, Luke Palmer wrote: : Chip Salzenberg writes: : I'm working on enhancing Perl6::Subs[*] to support more parameter : traits than just Cis required. I have some questions about : parameters and traits. (These questions all apply to pure Perl 6, : which I know I won't be able to translate completely, but I want to : know which target I'm missing.) : : * Given a parameter CArray @a, it's obvious I'm not allowed to : Cpush @a,1, because I didn't say Cis rw. But am I allowed to : C@a[0]++? How about C@a[0][0]++? How deep is read-only-ness? : : I believe that the default constant parameters is so we don't have to : construct lvalues out of our arguments when we call. So that probably : means that it's very shallow. : : On the language level, I've been thinking that it would be good to go : C's way and not allow any parameter modification whatsoever. The : problem is that in the presence of methods, we can't tell whether we : have to lvaluize anymore, so we're back to the Perl 5 trap of lvaluizing : everything. I think only predeclared simple subs are allowed to have rw parameters. Methods can have is ref parameters, but those don't require enforced lvaluehood on the caller end like rw does. : So if you want things modified, you'd have to pass in a reference. : Arrays and hashes would not generally have this restriction, since we : pass references of those guys anyway. Yes. : * Similarly, how deep is the copy implied by Cis copy? : : I think it's exactly as deep as read-only-ness. And both may be exactly as deep as COW. : * Do traits attach syntactically to the variable name, or to the : declaration as a whole? : : variable: @a is rw of Array : Array @a is rw : : declaration: @a of Array is rw : Array @a is rw : : Well, from this example it seems like `of` should be tighter than `is`. Traits are not allowed on ordinary rvalues, only on declarations. is traits always attach to the main declaration. of types always attach to the container on their immediate left. : * As far as I can tell, the choice of spelling an array parameter : CArray @a or CArray $a is entirely cosmetic: both @a and : $a are capable of holding an Array reference. Is there actually : a difference, e.g. in how they handle an undefined value? : : Hmmm... well I think all scalars are allowed to be undef. Arrays : aren't. So yeah, if you give @a undef, it probably gives you [] (or : croaks, but I don't think that's a good idea). If you give $a undef, it : gives you undef. As I mentioned in my other message, I think we should not assume that Perl 6 works the same in this regard as Perl 5 does. There needs to be something we can return that not only means (), but means also means You're hosed! (And here's why.) And I think we can make undef mean that if we make it lazily sensitive to scalar/list context (much like @a itself can be lazily sensitive to context). Hmm, maybe it would simpler to just tell everyone undef is a special empty lazy array that refuses to produce a value no matter how you ask. Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
LW == Larry Wall [EMAIL PROTECTED] writes: LW That being said, in Perl 5, if you say LW @a = undef; LW you don't get an undefined array. I'd like to make undef smart enough LW about list contexts that @a actually does end up undefined in Perl 6. LW That is, in scalar context, undef is a scalar value as in Perl 5, but LW in Perl 6, undef in list context means there isn't anything here if LW you try to look for it, so it's more like () in Perl 5, except that LW it also undefines the array if it's the only thing in the array. then how would you assign undef to the only element of the array? would this be needed: @a = ( undef ) ;# same as p5? vs. @a = undef ;# like undef @a in p5? i have always railed against undef on aggregates as it leads to using defined on them which is not the same as checking if an aggregate has any elements. i see that often in newbie code. in fact i would like to stop allowing undef as a function with args and have it only return a scalar undef value. there should be a different op to truly make an aggregate undefined (and i still don't see a need for that, emptying it is all that i ever think is needed). in my world undef is a scalar value and nothing else. how do you see it in p6? 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: Parameter and trait questions - just how 'only' _is_ 'read-only'?
LW == Larry Wall [EMAIL PROTECTED] writes: LW As I mentioned in my other message, I think we should not assume that LW Perl 6 works the same in this regard as Perl 5 does. There needs to be LW something we can return that not only means (), but means also means LW You're hosed! (And here's why.) And I think we can make undef mean LW that if we make it lazily sensitive to scalar/list context (much like @a LW itself can be lazily sensitive to context). LW Hmm, maybe it would simpler to just tell everyone undef is a special empty LW lazy array that refuses to produce a value no matter how you ask. why use undef for the error code? isn't this what exceptions are for? or setting $!? i actually use naked return as a postive thing in stem (string return values are bad and have the error string. it is consistant so it works). the problem with returning undef (or naked return) is that it is in-band data. now you could do a naked return but error thing. and then the called has to check for that property each time. but what does that mean when you do this (bad p6 code): sub return_error { return but error } my @a = return_error() ; is @a empty or what? how do you see the error in @a? i just don't like seeing undef used for error handling as it has too many other uses (even if i did it in stem). just make undef a scalar value and not a function nor a error marker. 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: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Sun, Mar 27, 2005 at 12:04:39AM -0500, Uri Guttman wrote: : LW == Larry Wall [EMAIL PROTECTED] writes: : : LW As I mentioned in my other message, I think we should not assume that : LW Perl 6 works the same in this regard as Perl 5 does. There needs to be : LW something we can return that not only means (), but means also means : LW You're hosed! (And here's why.) And I think we can make undef mean : LW that if we make it lazily sensitive to scalar/list context (much like @a : LW itself can be lazily sensitive to context). : : LW Hmm, maybe it would simpler to just tell everyone undef is a special empty : LW lazy array that refuses to produce a value no matter how you ask. : : why use undef for the error code? Because there's usually a reason why the undef was created, and it would be useful for the user to learn that. : isn't this what exceptions are for? Undef is a form of unthrown exception. Throwing things is often too violent for fail-soft situation. : or setting $!? $! is the current unthrown exception in Perl 6. (Or actually, it's also the thrown exception inside a CATCH block.) : i actually use naked return as a postive thing in stem : (string return values are bad and have the error string. it is : consistant so it works). Okay, so in this case you could hack around the problem because you don't want to return interesting good values. But sometimes you have both interesting good values and interesting bad values. Interesting values of undef solves that problem without having to send either the good data or the bad data out of band. : the problem with returning undef (or naked : return) is that it is in-band data. now you could do a naked return but : error thing. and then the called has to check for that property each : time. You should be checking your return values anyway, or useing fatal, which turns these unthrown exceptions into thrown ones. : but what does that mean when you do this (bad p6 code): : : sub return_error { return but error } That's written: sub return_error { fail What went wrong } which has the effect of sub return_error { return undef but Exception(What went wrong) } unless the caller uses fatal, in which case it's more like sub return_error { die(What went wrong) } : my @a = return_error() ; : : is @a empty or what? how do you see the error in @a? I am proposing that assigning a exceptional undef value (such as that returned by fail() above) to an array causes the array to become undefined. If you use that array somewhere else, it's as if you used the original unthrown exception. Eventually you get caught trying to do something defined with the undefined value and you get a nice message out saying where the original undefined value came from. : i just don't like seeing undef used for error handling as it has too : many other uses (even if i did it in stem). I don't see how the proposed semantics interfere with any other uses of undef. A bare scalar undef is still a very simple value. I don't see how you can simultaneously argue that it has many uses and yet has only one simple value. : just make undef a scalar value and not a function nor a error marker. fail(Language designer not persuaded);# :-) Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
On Sat, Mar 26, 2005 at 11:57:48PM -0500, Uri Guttman wrote: : LW == Larry Wall [EMAIL PROTECTED] writes: : : LW That being said, in Perl 5, if you say : : LW @a = undef; : : LW you don't get an undefined array. I'd like to make undef smart enough : LW about list contexts that @a actually does end up undefined in Perl 6. : LW That is, in scalar context, undef is a scalar value as in Perl 5, but : LW in Perl 6, undef in list context means there isn't anything here if : LW you try to look for it, so it's more like () in Perl 5, except that : LW it also undefines the array if it's the only thing in the array. : : then how would you assign undef to the only element of the array? would this : be needed: : : @a = ( undef ) ;# same as p5? : : vs. : @a = undef ;# like undef @a in p5? Those would do the same thing under the current proposal, since they're both in list context. If you really, really want a scalar undef value in list context, you could always say @a = scalar(undef); : i have always railed against undef on aggregates as it leads to using : defined on them which is not the same as checking if an aggregate has : any elements. i see that often in newbie code. Well, let's not confuse Perl 5's shortcomings with Perl 6's. I think we should fix the problem by making undef work a little more like the newbie expects, which is context dependent. : in fact i would like to : stop allowing undef as a function with args and have it only return a : scalar undef value. there should be a different op to truly make an : aggregate undefined (and i still don't see a need for that, emptying it : is all that i ever think is needed). We could certainly split out a separate undefine() function. We could even give it an optional argument that says *why* it's undefined, turning it into an unthrown exception, basically. We could use such a function to create interesting values of undef that are context sensitive. : in my world undef is a scalar value and nothing else. how do you see it : in p6? undef is not a scalar value, it is the explicit *absence* of a value where you expected one. In Perl 6, undef is the Bearer of Bad News. If you merely want undef for a scalar placeholder without negative connotations, I'd suggest something like class Empty {} my $nada = new Empty; instead. And $nada is the same length as undef. $X would be even shorter. On the other hand, Perl 6 is consistently returning booleans as 0 and 1 rather than and 1, so it's likely that constant 0 and 1 can be stored in less than a bit, as it were. So there might even be some kind of zero type that's essentially a value that's always 0, and takes no room to store at all. That might serve as a pretty good neutral placeholder. Larry
Re: Parameter and trait questions - just how 'only' _is_ 'read-only'?
LW == Larry Wall [EMAIL PROTECTED] writes: LW : then how would you assign undef to the only element of the LW array? would this : be needed: LW : LW : @a = ( undef ) ;# same as p5? LW : LW : vs. LW : @a = undef ;# like undef @a in p5? LW Those would do the same thing under the current proposal, since LW they're both in list context. If you really, really want a scalar LW undef value in list context, you could always say LW @a = scalar(undef); that works. i am starting to see what you mean by undef knowing about context. LW : in fact i would like to LW : stop allowing undef as a function with args and have it only return a LW : scalar undef value. there should be a different op to truly make an LW : aggregate undefined (and i still don't see a need for that, emptying it LW : is all that i ever think is needed). LW We could certainly split out a separate undefine() function. We could LW even give it an optional argument that says *why* it's undefined, turning LW it into an unthrown exception, basically. We could use such a function LW to create interesting values of undef that are context sensitive. that split makes sense as you are now using undef as a special (or as you say below unexpected) value. so it shouldn't also be overloaded as a function operating on variables. just doing the split will make me happier (if you are so benevolent as to care about my happiness :). LW : in my world undef is a scalar value and nothing else. how do you see it LW : in p6? LW undef is not a scalar value, it is the explicit *absence* of a value LW where you expected one. In Perl 6, undef is the Bearer of Bad News. oy! i feel the pain of the late night phone call. :) 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