Re: clarifying the spec for 'ref'
HaloO, Luke Palmer wrote: Removing abilities, counterintuitive though it may seem on the surface, makes the type *larger*. It is not adding constraints, it is removing them (you might not be able to call set($x) on this object anymore). Welcome to the co- and contra-variance problem again. We must distinguish two sets: (1) the set of all conceivable instances (2) the set of constraints Larry means (2) while Luke is talking about (1) in the particular case of record subtyping I think. That is methods are arrow typed slots of the object record (That is they have type :(Object --> ::X --> ::Y)). Interestingly Perl6 doesn't provide a sound sublanguage for defining constraints in a way that is amenable for predicate dispatch. I would expect the where blocks to be under very strict control of the type system but seemingly they aren't. In order to resolve the linguistic conundrum of "when Array", we could say that the Array role in fact implements a constant Array. If you would like to be a mutable array, you implement MutableArray or something. That would make code like this: given $x { when Array { $x[42] = 42; } } broken from a pure point of view. You may not be able to set element 42 of that array. Perl would still allow the code to compile, of course, because Perl is a laid-back language. The point is that reference types are co-variant for reading and contra-variant for writing. The only escape for rw access is mandating type equality which in Perl6 comes as 'does Array' and has got the rw interface. Constness is something that exists, so we have to solve it somehow. Yes, but it's only half the story! The other thing that has to be solved is writeonlyness. Both in isolation result in type soundness in the presence of subtype directed dispatch. But both at the same time lose this and mandate type equality. Note that a rw Array is nicely applicable where either a readonly or writeonly subtype is expected. The only difference is in the return type handling, of course! Also sharing parts of the Array implementation is orthogonal to the question of subtyping. But pretending that const arrays are arrays with the added capability that they throw an error when you try to write to them is going to get us to a broken type model. I think type inference should be strong enough to find out that an Array parameter of a sub is consistently used readonly or writeonly and advertise this property accordingly to the typechecker and the dispatcher. Regards, --
Re: clarifying the spec for 'ref'
Richard Hainsworth skribis 2006-08-28 10:33 (+0400): > --- > | Class > A| > | > -- | > || Class B > | | > | > -- | > -- > Your mail program is wrapping this in a way that renders it unusable. Please make sure you use a monospaced font, and do not exceed the wrapping limit (typically 72 characters). > - > -| Class D | > | Class A | || > | > |---|-| > || > |-| > | --|- > | | > ---|-|-|- > | > | | | Class > B | > | > --| > |Class C | > I'm curious what this was supposed to look like. :) Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: clarifying the spec for 'ref'
With regard to the 'square' 'isa' 'rectangle' or vice versa question, surely it is for the programmer to decide depending on the situation. Though the problem is how to define criteria for trapping problems at compile time. Regarding classes and roles, and in fact multiple inheritance in general, I am still unclear. For my own understanding, I have tried to analyse various situations using the idea of sets and subsets and Venn diagrams for demonstrating the relations between sets and subsets (please forgive the icky character graphics). case 1 (Class B is a subset of class A): --- | Class A| | -- | || Class B | | | -- | -- My understanding of inheritance in other languages: Class A 'isa' Class B, and inherits all of the attributes and functionality of Class B, and extends functionality and attributes. It is also possible for Class B to be ('isa') Class A, and ignore the extra functionality of A. Though why one would want to do this is unclear. My suggested interpretation of roles: Class B is a role, and Class A is built from Class B, extending its functionality. case 2 (Class A and Class B intersect): -- | Class A | | |- || Class A U Class B || || || -|--- | |Class B| -- Usual OO technique: This Class B inherits the functionality of Class A, but then over-rides (anuls) some of the functionality of A. Especially, if functionality in B is named in the same way as in A. Question: Is this the sort of behaviour that is forbidden in some languages. Role-playing programming: For the sake of programming sanity / ease of debugging, both Classes A & B are built from a role that represents their intersection ( Class A U Class B), and then code is added in the definitions of the classes to extend the functionality - possibly using over-riding with same-name methods/attributes for different types. case 3 (multiple subsets): --- | Class A| | -- | || Class B | | | -- | | -- | || Class C | | | -- | | -- | || Class D | | | -- | -- This would require multiple inheritance. In perl6 (I think), Class A would be built from the 'roles' of classes B-D. But the question is what would 'ref' return? Would it only define a match for class A, or would it recognise the existence of Classes B-D? If so, how? case 4 (multiple intersecting sets - only four shown): - -| Class D | | Class A | || | |---|-| || |-| | --|- | | ---|-|-|- | | | | Class B | | --| |Class C
Re: clarifying the spec for 'ref'
On 8/25/06, Daniel Hulme <[EMAIL PROTECTED]> wrote: That's because you're used to one way of thinking about class inheritance: that the subclass can do everything that the superclass can do, and more. In this scheme, you might have a Square class, with a field representing its corner and another giving its side length. Then, you could build on this to have Rectangle as a subclass, which adds an extra side length, and extra accessors for it. This is a really bad way of making your subclasses work, but your Rectangle has all the fields and methods of your Square, and some extra ones. This is the well-known Circle/Ellipse problem, and it relates to the theory of value types. We'll first take the traditional conception that a Square is a Rectangle, the opposite of your viewpoint. This is based on the geometrical definitions of these shapes. This makes sense from a usage standpoint: sub rect_perimiter(Rectangle $x) { 2*$x.width + 2*$x.height; } sub square_perimiter(Square $x) { 4*$x.width; } It makes sense to pass a Square to rect_perimiter, but not to pass a Rectangle to square_perimiter. That is one indication that Square is a subtype of Rectangle. However, say that Rectangle had set_height() and set_width() methods. You cannot set the height and width of a square independently, so a function like this: sub make_dims(Rectangle $r, $w, $h) { $r.set_width($w); $r.set_height($h); POST { $r.area == $w * $h } } Must fail if $w and $h are not equal (and depending on Square's implementation, might fail if they are equal). You could say that the failure is on the implementation side: we couldn't implement set_width and set_height appropriately. So clearly a Square is not a Rectangle. Let's look at the other way around (your viewpoint): a Rectangle is a Square. This makes sense from an implementation point of view, as you point out. We just take Square's methods and add a couple of capabilites. However: sub area(Square $x) { $x.width ** 2; } Fails (by returning the wrong thing, worse than dying) if you pass it a Rectangle. So it failed from the usage point of view. You could say "that should be a method", but then you should say that everything that uses a square should be a method of square, because we must be able to make assumptions about the behavior of classes. If you say that my sub makes an assumption that it shouldn't, realize that the only thing it is assuming is that a Square is a geometrical square. If I can't make that assumption, then Square is not a very good name for that class. So clearly a Rectangle is not a Square. One way failed on the implementation side, the other on the usage side. I'd argue that the "Rectangle is a Square" view's validity can only be argued from an implementation laziness point of view (which is okay, but it must also be balanced with other issues). The "Square is a Rectangle" point of view only works if they are value types: if you are not allowed to modify anything. In that circumstance, it works very cleanly[1]. But if you are allowed to modify things, then the two classes must be siblings, not parent-child related. Luke
Re: clarifying the spec for 'ref'
On 8/25/06, Mark J. Reed <[EMAIL PROTECTED]> wrote: Why not? Is it any weirder than simply changing that functionality beyond recognition? You can always fake removing functionality even if the language doesn't actually support it. Yes, yes, of course. That is not the issue. We are trying to determine whether Array is a subtype of Array::Const. There are many things you *can* do, but for core language features, it is probably not a good idea to abandon OO foundations so quickly. Larry says that a type that removes functionality is not a "subtype" but a "subset". But that is bogus. Let's consider this class: class Accessor { has $:x; method set($x) { $.x = $x } method get() { $:x } } And let's define Accessors = the set of all objects on which you can call set($x) and get(). That's not strictly the case, because there may be other objects which are not Accessors which might have those methods, but we can ignore that for the time being. Now let's say there is another type, ConstAccessor, which removes the set($x) ability, creating a "subset". ConstAccessors is now the set of things on which you can call get(). And now look at the sets: Accessors = the set of all objects on which you can call both set($x) and get(). ConstAccessors = the set of all objects on which you can call get(). Clearly Accessors is a subset of ConstAccessors, because anything you can call set($x) and get() on you can call get() on. Removing abilities, counterintuitive though it may seem on the surface, makes the type *larger*. It is not adding constraints, it is removing them (you might not be able to call set($x) on this object anymore). There are many ways to think about this. You can indeed take a superclass which defines a method and override that method with one that pretends the method doesn't exist, or throws some other kind of error. But that is a pure OO no-no; you were guaranteeing from the superclass that you could safely call a method, and then the subclass violated that guarantee. Fortunately, Perl is not pure OO, so we are allowed to do that in our code, but I don't think it's a good idea to start following the faulty line of reasoning that a constant something is a subtype of its nonconstant counterpart. In order to resolve the linguistic conundrum of "when Array", we could say that the Array role in fact implements a constant Array. If you would like to be a mutable array, you implement MutableArray or something. That would make code like this: given $x { when Array { $x[42] = 42; } } broken from a pure point of view. You may not be able to set element 42 of that array. Perl would still allow the code to compile, of course, because Perl is a laid-back language. Constness is something that exists, so we have to solve it somehow. My experience with C++ tells me that the best way to solve it is to keep it out of the way most of the time (which C++ does not). The solution above is one way to do that, there may be others. But pretending that const arrays are arrays with the added capability that they throw an error when you try to write to them is going to get us to a broken type model. Luke
Re: clarifying the spec for 'ref'
On Fri, Aug 25, 2006 at 01:25:23PM -0700, Trey Harris wrote: : I think Larry nailed it with his observation about the difference between : class and role and trait. 'Constant' is a trait of another type, not a : type into itself. Hmm, well, there are several hands to be waved here. First, there's more than one kind of constancy. Some types are intrinsically immutable, some are immutable by compile-time declaration, some are just immutable by contract, while others are operationally constant because you never happen to call any mutators. I'd like to distinguish the latter by calling it "readonly" rather than "constant" or "immutable". The big handwave about roles is that they can simultaneosly serve as your abstract array and your concrete default implementation through the magic of class/role punning. (It occurs to me that we probably need to nail down the genericity (or lack thereof) of PRE and POST blocks when attached to roles rather than classes. But in theory roles are allowed to participate in DBC, I think.) The big handwave about subsets is that they are basically defined operationally rather than contractually. When I use a subset type, the constraints are something I'm enforcing on myself, not something enforced by the underlying base class. The actual class knows nothing about my personal hangups. An Odd is only odd to me, not to the value, which only knows it's an Int. You don't do DBC with subsets. You're just being extra-disciplined outside of any contractual agreements. That's how I see it, anyway. Larry
Re: clarifying the spec for 'ref'
On Fri, Aug 25, 2006 at 02:04:01PM -0700, Trey Harris wrote: : In any case, Larry's settled this issue. Nah, I just handwaved it harder. :) Larry
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, Juerd writes: Trey Harris skribis 2006-08-25 13:26 (-0700): Explain to me how "nontraditional" DBC might work in an internally consistent way. Otherwise, this is hand-waving. :-) Perl *is* hand-waving. Yeah, but hand-waving on how it manages the behavior it exhibits. The behavior itself should be defined and internally consistent. To wit, you should be able to write a test. I can't figure out what a test for a hypothetical nontraditional DBC would look like. In any case, Larry's settled this issue. Trey
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, Daniel Hulme writes: If "changing that functionality beyond recognition" means changing its external behavior (as opposed to its internal behavior) so that it acts differently from what the superclass had promised to do, then no, it's not any weirder--but I can't figure out how the contract would work, either. That's because you're used to one way of thinking about class inheritance: that the subclass can do everything that the superclass can do, and more. In this scheme, you might have a Square class, with a field representing its corner and another giving its side length. Then, you could build on this to have Rectangle as a subclass, which adds an extra side length, and extra accessors for it. This is a really bad way of making your subclasses work, but your Rectangle has all the fields and methods of your Square, and some extra ones. Mmmm, no... depending on usage, I'd most probably have Shape->Polygon->Regular->Square, and Shape->Polygon->Rectangle, and write a FourSided role (perhaps a subrole of the Sided role, or maybe Sided can be parameterized so that Sided<4> could work) to capture the code that can be shared between Squares and Rectangles. I'm saying that subclasses *must* extend the promised capabilities of their parent classes, but that extending capability shouldn't be the only determinant of when you extend and when you make a sibling or a role or a trait. But yes, if you didn't want to have any branching in your inheritance pole (not tree), you'd have to make Square the superclass of Rectangle. Another way of looking at it is that the Rectangle is the more generalised one, so it should be the superclass. It has a corner and two side lengths, and associated accessors. Now, your Square is a subclass of this. A Square in this scheme isa Rectangle, with the constraint that the two side lengths are always equal. (Never mind the storage considerations: that's internal.) The problem comes up when code tries to do this: sub stretchWidth (Rectangle $r, Rat $ratio) { PRE { $ratio > 0 } $r.w *= $ratio; POST { now($r.w) == before($r.w) * $ratio and now($r.h) == before($r.h)} } The pre and postconditions make perfect sense in the context of a Rectangle--we need a positive stretch ratio, and only the width will be modified, not the height. But then: for any(@shapes) ~~ Rectangle -> $s { stretchWidth($s, 2); } Again, looks perfectly reasonable--but one of @shapes was a Square, which is also a Rectangle. Hit that one, POST fails, and boom! Either .w is going to fail for being unmodifyable, or .w and .h are both bindings to .side, and so stretchWidth's postcondition will fail. Most languages use the first scheme of class inheritance, but some offer the second. Perl 6, AFAICS, has the first for subclasses, but offers the second with subtypes and where clauses. I don't believe I've previously used a language that offered both, so I'm interested to see how this conjunction of features will turn out. Yep. I'm excited. Trey
Re: clarifying the spec for 'ref'
Trey Harris skribis 2006-08-25 13:26 (-0700): > Explain to me how "nontraditional" DBC might work in an internally > consistent way. Otherwise, this is hand-waving. :-) Perl *is* hand-waving.
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, Juerd writes: Trey Harris skribis 2006-08-25 11:33 (-0700): Ok... same thing from a DBC perspective. Subclasses can add functionality (by AND'ing postconditions), or remove constraints (by OR'ing preconditions), but they can't traditionally remove functionality or add constraints. I just want to read about how that works. The keyword is "traditionally". We're used to a dynamic language that bends the rules all the time, including runtime. Why would Perl stick to academic limitations, while optimizing for the most common use is the standard? my Array::Const @foo; @foo ~~ Array; # False?! Please, no. Though in practice I expect "is ro" to be used, not a subtype or subset. Explain to me how "nontraditional" DBC might work in an internally consistent way. Otherwise, this is hand-waving. :-) Trey
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, Mark J. Reed writes: OK, I admit I wasn't thinking about things from a DBC perspective, and misunderstood "DBC" to be a reference to some database module. I here am new and I didn't have context. My bad. But if we're talking design-by-contract, I don't see how "Array is Array::Const" can work, either, since I consider the inability to modify the elements of a constant array an explicit part of its contract. Well, usually you don't specify things an object *can't* do as part of its contract, unless those things would be judged harmful if allowed. (See below). You might specify the contract of the ConstArray by saying that after any of the methods offered have been called, particular values will be unchanged--but that feature would maintain for non-constant subclasses. In other words, .elems could be specified at the constant superclass level, and its contract might say that .elems won't modify the elements, but that part of the .elems POST will maintain even in non-constant subclasses. A rw accessor, on the other hand, would not even be specified in the constant superclass, so the ConstArray contract would have nothing to say about modification. Therefore, if we're supporting DBC, I would say that Array and Array::Const should not have an is-a relationship at all, but should be sibling classes, inheriting from an abstract sequence-type parent class whose definition makes no statements one way or the other about modifications to elements. Sure. One *could* write a superclass, say "AbstractArrayThing", that could not be instantiated and would have no mutating methods, and have its PRE and POST blocks written as I mentioned above. The ConstArray would be a subclass that would simply add a constructor. You could specify its ongoing constedness explicitly by a class invariant block (not currently specified in Synopses, but such a thing often exists in DBC and could be constructed from a combo of ENTER and LEAVE at the class level) saying that the array will still be the same array before and after every method call. I think that probably makes most sense and avoids the "Array isa ConstArray" cognitive dissonance. But then people would have to get into the habit of writing "AbstractArrayThing" when they want to allow for constant arrays to be passed in. That way lies the madness of Java where you're constantly writing factories to warp something so that it conforms to the API of this other thing merely because it happens to live in the wrong part of the class heirarchy. I think Larry nailed it with his observation about the difference between class and role and trait. 'Constant' is a trait of another type, not a type into itself. Trey
Re: clarifying the spec for 'ref'
Trey Harris skribis 2006-08-25 11:33 (-0700): > Ok... same thing from a DBC perspective. Subclasses can add functionality > (by AND'ing postconditions), or remove constraints (by OR'ing > preconditions), but they can't traditionally remove functionality or add > constraints. I just want to read about how that works. The keyword is "traditionally". We're used to a dynamic language that bends the rules all the time, including runtime. Why would Perl stick to academic limitations, while optimizing for the most common use is the standard? my Array::Const @foo; @foo ~~ Array; # False?! Please, no. Though in practice I expect "is ro" to be used, not a subtype or subset. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: clarifying the spec for 'ref'
> If "changing that functionality beyond recognition" means changing its > external behavior (as opposed to its internal behavior) so that it > acts differently from what the superclass had promised to do, then > no, it's not any weirder--but I can't figure out how the contract > would work, either. That's because you're used to one way of thinking about class inheritance: that the subclass can do everything that the superclass can do, and more. In this scheme, you might have a Square class, with a field representing its corner and another giving its side length. Then, you could build on this to have Rectangle as a subclass, which adds an extra side length, and extra accessors for it. This is a really bad way of making your subclasses work, but your Rectangle has all the fields and methods of your Square, and some extra ones. Another way of looking at it is that the Rectangle is the more generalised one, so it should be the superclass. It has a corner and two side lengths, and associated accessors. Now, your Square is a subclass of this. A Square in this scheme isa Rectangle, with the constraint that the two side lengths are always equal. (Never mind the storage considerations: that's internal.) In the first scheme, even though the subclass only adds capabilities, it breaks the isa relation, because a (real-world) rectangle is not necessarily a square. If you write code that takes a Square, and you give it a Rectangle, all the function calls will still work, but the functionality will be wrong, because it makes assumptions that are no longer true. In the second scheme, the isa relation holds on the real-world things you're abstracting, because a (real-world) square isa rectangle. But the assumption you want to make, that you can call any superclass method on the subclass, no longer really works. (As people said, you can hack around it, but fundamentally it's wrong.) So, if you write code that wants a Rectangle, and you give it a Square, you have to pussy-foot around this externally imposed constraint, but the (smaller set of) assumptions still hold. Most languages use the first scheme of class inheritance, but some offer the second. Perl 6, AFAICS, has the first for subclasses, but offers the second with subtypes and where clauses. I don't believe I've previously used a language that offered both, so I'm interested to see how this conjunction of features will turn out. -- "For God's sake, please give it up. Fear it no less than the sensual passion, because it, too, may take up all your time and deprive you of your health, peace of mind and happiness in life." Wolfgang Bolyai, urging his son to give up his research on non-Euclidean geometry pgp1H7z9PSBdI.pgp Description: PGP signature
Re: clarifying the spec for 'ref'
On 8/25/06, Mark J. Reed <[EMAIL PROTECTED]> wrote: I here am new and I didn't have context. Well, technically, I here am not new; I've been here since before Apoc 1. But I hadn't been paying close attention for a while until recently. :) Either way, I didn't get the ref. -- Mark J. Reed <[EMAIL PROTECTED]>
Re: clarifying the spec for 'ref'
OK, I admit I wasn't thinking about things from a DBC perspective, and misunderstood "DBC" to be a reference to some database module. I here am new and I didn't have context. My bad. But if we're talking design-by-contract, I don't see how "Array is Array::Const" can work, either, since I consider the inability to modify the elements of a constant array an explicit part of its contract. Therefore, if we're supporting DBC, I would say that Array and Array::Const should not have an is-a relationship at all, but should be sibling classes, inheriting from an abstract sequence-type parent class whose definition makes no statements one way or the other about modifications to elements.
Re: clarifying the spec for 'ref'
On Fri, Aug 25, 2006 at 12:38:33PM -0700, Trey Harris wrote: : But in order to allow that choice, the language has to impose some : groundrules for everyone. strict couldn't exist in Perl 5 if lexicals : could autovivify. And--*by my understanding of DBC*--subclasses can't : remove promised functionality or impose surprising constraints. So a) : Perl 6 can't support DBC, contrary to the Synopses, b) you can't remove : functionality or impose new constraints in subclasses, or c) my : understanding of DBC is incorrect. In Perl 6, option b is deemed to be correct, but allow me to reiterate that: 1) a role is not a superclass 2) a subset is not a subclass Larry
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, Mark J. Reed writes: On 8/25/06, Trey Harris <[EMAIL PROTECTED]> wrote: > subclasses can remove functionality as well as adding it Can someone suggest some reading I can do to understand how that works? I can't wrap my head around the idea of subclasses removing functionality. Why not? Is it any weirder than simply changing that functionality beyond recognition? If "changing that functionality beyond recognition" means changing its external behavior (as opposed to its internal behavior) so that it acts differently from what the superclass had promised to do, then no, it's not any weirder--but I can't figure out how the contract would work, either. To extend the "contract" analogy, if I lease you a house, I may allow you to sublease the house, and I may even agree to take my rent directly from the sublessee rather than from you. But the sublessee can't just say to me, "yeah, so, I'm going to pay you 1000 yen, not 1000 dollars," and expect me to just put up with it or work around the missing money. I made assumptions based on the original contract. If the sublessee says he wants to pay me more or more promptly or in cash under the table, great. If he wants to listen to opera in the evenings instead of of watching TV, that's internal behavior having nothing to do with our contract and I don't care. The changes have to be either in my favor or irrelevant to the contract. Otherwise, I'm going to demand we renegotiate--in other words, that you don't pretend to be a superclass whose behavior you're not willing to emulate, so that when I see you I can treat you as what you are, not what you're pretending to be. "isa" means "is a". It doesn't mean "is roughly of a class analogous to". You can always fake removing functionality even if the language doesn't actually support it. Consider: class Super { method something {...} } class Sub is Super { method something { throw new MissingMethodException; } } or whatever that ends up looking like. In Ruby and C++, a subclass can make a method private that is public in its superclass, effectively removing it. (Java disallows such shenanigans). But why would you want to, just because "ConstArray isa Array, not the other way around" just feels right? "Pluto isa Planet" feels right too, but one can't construct a reasonable definition that doesn't pull things in that you don't want to consider Planets. Remember, one of the goals of Perl 6 is to make it more friendly to very large software projects. "Java disallows such shenanigans" is one example of precisely why Java has become so popular for large projects. (The exception-throwing example is clearly, well, an exception, and you can always do that.) When software gets large, you need to be able to impose some constraints on behavior. Maybe this is a stricture or something. In any case, I'm not trying to make a ideological argument here. I don't care if you can remove functionality or add constraints if that helps me get my job done (I'm just skeptical that it will). I just want to think about the DBC features of Perl 6, and I don't know how they could work in the context of loosening contracts in subclasses, and I'd like somebody to point me to how, that's all. Design-by-Contract is all about formal definitions. Does this mean you can't [...] expect foo($obj) to work Of course you can expect foo($obj) to work. It might not, if the subclass definition does something weird, but that's always the case whether "removing functionality" is on the table or not, and it's no reason to change your reasonable expectations. You can be paranoid about it if you want, but it's not a very Perlish form of paranoia. (Yes, there are Perlish forms of paranoia. Taintedness checking, for instance...) When I said "expect it to work", that was shorthand for "it *will* work, in the absence of a bug". That's what DBC is all about--that one can program based on the expectations of the contract, and you don't have to write error-catching code every single time you use an object's exported functionality. I'll agree that DBC isn't very Perlish, in much the same way that strict was not very Perlish in Perl 5 (for at least the first five years of its existence, and probably even till today). But in Perl 6 strict is the default, so by definition now Perlish. :-) If DBC is in the language, then some people will use it, most people won't because they don't like the inconvenience, and over time if it actually results in more solid software, more people will choose to adopt it (like strict). But in order to allow that choice, the language has to impose some groundrules for everyone. strict couldn't exist in Perl 5 if lexicals could autovivify. And--*by my understanding of DBC*--subclasses can't remove promised functionality or impose surprising constraints. So a) Perl 6 can't support DBC, contrary to the Synopses, b) you ca
Re: clarifying the spec for 'ref'
> Does this mean you can't write > >class Super { method something { ... } } > >sub foo (Super $bar) { $bar.something() } > > and expect foo($obj) to work, because $obj might be: > >class Sub is Super { # remove .something--how does that happen? } > >foo($obj); # Boom!? > > So what happens? For the case in point if you tried to call @array.set(0, $element) I would expect it to fail with an error saying you can't modify a constant array. The method set still exists - it just politely tells you not to call that method on that particular class. No methods are removed. This is very similar to read only strings. Paul Seamons
Re: clarifying the spec for 'ref'
On 8/25/06, Trey Harris <[EMAIL PROTECTED]> wrote: > subclasses can remove functionality as well as adding it Can someone suggest some reading I can do to understand how that works? I can't wrap my head around the idea of subclasses removing functionality. Why not? Is it any weirder than simply changing that functionality beyond recognition? You can always fake removing functionality even if the language doesn't actually support it. Consider: class Super { method something {...} } class Sub is Super { method something { throw new MissingMethodException; } } or whatever that ends up looking like. In Ruby and C++, a subclass can make a method private that is public in its superclass, effectively removing it. (Java disallows such shenanigans). Does this mean you can't write class Super { method something { ... } } sub foo (Super $bar) { $bar.something() } and expect foo($obj) to work Of course you can expect foo($obj) to work. It might not, if the subclass definition does something weird, but that's always the case whether "removing functionality" is on the table or not, and it's no reason to change your reasonable expectations. You can be paranoid about it if you want, but it's not a very Perlish form of paranoia. (Yes, there are Perlish forms of paranoia. Taintedness checking, for instance...) -- Mark J. Reed <[EMAIL PROTECTED]>
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, jerry gay writes: perhaps trey meant "subclasses can add constraints as well as functionality" instead of "subclasses can remove functionality as well as adding it." just a guess. ~jerry Ok... same thing from a DBC perspective. Subclasses can add functionality (by AND'ing postconditions), or remove constraints (by OR'ing preconditions), but they can't traditionally remove functionality or add constraints. I just want to read about how that works. Trey
Re: clarifying the spec for 'ref'
On 8/25/06, Trey Harris <[EMAIL PROTECTED]> wrote: In a message dated Fri, 25 Aug 2006, Mark J. Reed writes: > I think the justification for Luke's POV is the number of operations > each class provides. But my perspective agrees with Juerd - > subclasses can remove functionality as well as adding it, and I > definitely view "constant" as an add-on modifier, not a default that > has to be overridden. Can someone suggest some reading I can do to understand how that works? I can't wrap my head around the idea of subclasses removing functionality. perhaps trey meant "subclasses can add constraints as well as functionality" instead of "subclasses can remove functionality as well as adding it." just a guess. ~jerry
Re: clarifying the spec for 'ref'
In a message dated Fri, 25 Aug 2006, Mark J. Reed writes: I think the justification for Luke's POV is the number of operations each class provides. But my perspective agrees with Juerd - subclasses can remove functionality as well as adding it, and I definitely view "constant" as an add-on modifier, not a default that has to be overridden. Can someone suggest some reading I can do to understand how that works? I can't wrap my head around the idea of subclasses removing functionality. Does this mean you can't write class Super { method something { ... } } sub foo (Super $bar) { $bar.something() } and expect foo($obj) to work, because $obj might be: class Sub is Super { # remove .something--how does that happen? } foo($obj); # Boom!? So what happens? Do you arrange somehow for polymorphism to be interrupted, so that the call to foo() acts as though there was a nonconformant type? Does foo() get scanned somehow to notice that .something() is getting called, and $obj doesn't support .something, so that bubbles up such that foo() can't be called in the first place? (If that's true, how do you do duck-typing, since duck-typing code almost by definition has branches that would call such invalid methods?) I had been toying with writing some tests for the DBC blocks. But the idea of removing functionality from a subclass completely blows away my understanding of DBC, so I'd particularly like some reading to help me understand how DBC works in a language that lets you remove functionality. Trey
Re: clarifying the spec for 'ref'
On Fri, Aug 25, 2006 at 08:40:59AM -0400, Mark J. Reed wrote: : On 8/25/06, Juerd <[EMAIL PROTECTED]> wrote: : >You define in terms of functionality, but don't provide an explanation : >for the chosen point of view. One could say that constant arrays protect : >against : >modifications, which normal arrays don't. Hence, constant arrays do *more*. : : I think the justification for Luke's POV is the number of operations : each class provides. But my perspective agrees with Juerd - : subclasses can remove functionality as well as adding it, and I : definitely view "constant" as an add-on modifier, not a default that : has to be overridden. And in my view, types that remove functionality aren't called "subclasses" but rather "subsets", and actually have the same underlying actual class, but with different constraints. Another view of the Array problem is that $x ~~ Array is testing against the Array role rather than the Array class, and that the Array class is just the default implementation of the Array role. Array::Const is just a different implementation, like a tie. So there are at least two ways in Perl 6 to sneak around strict Liskovism. Larry
Re: clarifying the spec for 'ref'
On 8/25/06, Juerd <[EMAIL PROTECTED]> wrote: You define in terms of functionality, but don't provide an explanation for the chosen point of view. One could say that constant arrays protect against modifications, which normal arrays don't. Hence, constant arrays do *more*. I think the justification for Luke's POV is the number of operations each class provides. But my perspective agrees with Juerd - subclasses can remove functionality as well as adding it, and I definitely view "constant" as an add-on modifier, not a default that has to be overridden. -- Mark J. Reed <[EMAIL PROTECTED]>
Re: clarifying the spec for 'ref'
Luke Palmer skribis 2006-08-24 23:57 (-0600): > Let's say our arrays are simple, for argument's sake: With a constant > array, you can: > * get its length > * get the value of an element at an index > With an array, you can: > * get its length > * get the value of an element at an index > * set the value of an element at an index You define in terms of functionality, but don't provide an explanation for the chosen point of view. One could say that constant arrays protect against modifications, which normal arrays don't. Hence, constant arrays do *more*. Juerd -- http://convolution.nl/maak_juerd_blij.html http://convolution.nl/make_juerd_happy.html http://convolution.nl/gajigu_juerd_n.html
Re: clarifying the spec for 'ref'
On 8/24/06, Mark J. Reed <[EMAIL PROTECTED]> wrote: On 8/24/06, Luke Palmer <[EMAIL PROTECTED]> wrote: > Well, actually Array would be a subtype of Array::Const, not t'other > way round. Why? That makes no sense to me. An Array isn't a variety of constant Array; a constant Array is a variety of Array... Let's say our arrays are simple, for argument's sake: With a constant array, you can: * get its length * get the value of an element at an index With an array, you can: * get its length * get the value of an element at an index * set the value of an element at an index That is, arrays have strictly more capabilites than constant arrays. Every array can be used as a constant array, but not every constant array can be used as an array. You can see this recognized in C++: int* x; const int* y; x = y; // illegal y = x; // okay Luke
Re: clarifying the spec for 'ref'
On 8/24/06, Luke Palmer <[EMAIL PROTECTED]> wrote: Well, actually Array would be a subtype of Array::Const, not t'other way round. Why? That makes no sense to me. An Array isn't a variety of constant Array; a constant Array is a variety of Array... Anyway, while smart matching with ~~ would be the usual way to go, I suppose you could also do an explicit equality check with .^/.META... -- Mark J. Reed <[EMAIL PROTECTED]>
Re: clarifying the spec for 'ref'
On 8/23/06, Larry Wall <[EMAIL PROTECTED]> wrote: you really want: if $a ~~ Array { and that also matches Array::Const, assuming it's derived from Array. Well, actually Array would be a subtype of Array::Const, not t'other way round. That is a little bit disconcerting, because when you say $a ~~ Array, you probably want the const ones too. I'm not in a state of mind to resolve the issue at the moment, but I'll happily point it out. :-) Luke
Re: clarifying the spec for 'ref'
On Wed, Aug 23, 2006 at 06:20:55PM -0400, Mark Stosberg wrote: : I noticed in pugs, 'ref' does not return 'HASH' and 'ARRAY' as Perl5 : does, but returns values including 'Hash', 'Array' and 'Array::Const'. Well, first of all, ref is going away entirely, since there's no such thing as a reference in Perl 6 (or everything is a reference, looking at it the other way), so in a boolean context it would be trivially true (or false) for everything. Its use to return the type of the referent is then completely misnamed. And even for that use, returning a string is wrong. It should return the type itself, and that should stringify to the type name if you use it in string context. Which mostly you don't want to. Anyway, .ref is likely to end up with a name like .what or .WHAT instead. (And .SKID is probably changing to .WHO or .WHICH at the same time. And maybe .META gets renamed .HOW while we're at it. Maybe .WHERE gives you the memory address, or the url, or something. As for .WHY, well, .WHYNOT? :-) : I don't find meaningful mentions of 'HASH' and 'ARRAY' by grep'ing : docs/Perl6 (or even "ref"!), so I wanted to check in here about the : meaningfulness of this change. It's meaningful. There is no longer a distinction between fake types naming internal forms and real types. So we renamed the formerly fake types to look more like real types, because they are. : Personally, I dislike the change from HASH to 'Hash' because it seems to : be change without a significant benefit. It's annoyingly different. Oh, if that's your smallest annoyance, please count yourself lucky. :) : The ARRAY case is worse, because it seems I now need to write this: : : if ref $a eq any('Array','Array::Const') { You're in P5-think here in assuming that type names are merely strings. In P6-think you just want to treat the type as a first class object. In particular, smart match already does what you want and handles inheritance for you. Instead of saying if ref $a eq 'ARRAY' { you really want: if $a ~~ Array { and that also matches Array::Const, assuming it's derived from Array. : If you are interested, here's code which illustrates cases when : 'Array' is returned, versus 'Array::Const' : : my $a = []; : my $b = \@('b'); : : say ref $a; : say ref $b; : : I'd like for 'HASH' and 'ARRAY' to keep working, or for the Perl6 docs : to justify the change. The justifications are mostly off in the Apocalypses. Use of types in smartmatching is mostly discussed in A04, for instance. But the synopses are primarily intended contain just the changes, not the rationale for the changes. Larry