If you forget to initialise a variable which you thought was a Dictionary - you get a confusing error message: "Error: only integers should be used as indices” if you try an at:put: This is a consequence of having at:put: defined on Object (which is a bit nasty) Should UndefinedObject at least override this and signal something a bit more obvious? This is a common and easily done thing and we don't support it very well. I just did it in some code, and was scratching my head initially until I read the stack properly and realised it was something much simpler than I thought I had done. Any thoughts on this?
|
I understand #basicAt:[put:] being in Object, but I never understood #at:[put:] being there. GNU Smalltalk: st> nil at: 1 Object: nil error: Invalid value nil: object not indexable In my Smalltalk, you get a DNU. In Squeak you get a debugger window with title Error: instances of UndefinedObject are not indexable The same for Boolean, Character, and Integer, except Squeak where (20 factorial at: 1) answers 0 (oh dear oh dear oh dear). In VW you get a "Subscript out of bounds" error, which is disappointing, as do true and $a, but a LargePositiveinteger gets #shouldNotImplement. On Tue, 12 Mar 2019 at 15:28, Tim Mackinnon <[hidden email]> wrote:
|
Hi,
Yes, I do not like it… I think it is there so that you can just make a variable subclass and at: / at:put: will work without having to re-implement them… Marcus
|
On Tue, 12 Mar 2019 at 21:56, Marcus Denker <[hidden email]> wrote:
> > Hi, > > Yes, I do not like it… I think it is there so that you can just make a variable subclass and at: / at:put: will work without > having to re-implement them… So we should consider... * how often are variable subclasses created ? by novices or experts ? * how much work is it to reimplement those methods ? how difficult to know what needs to be done ? * what is the balance cheers -ben > > Marcus > > On 12 Mar 2019, at 04:55, Richard O'Keefe <[hidden email]> wrote: > > I understand #basicAt:[put:] being in Object, but I never understood #at:[put:] being there. > GNU Smalltalk: > st> nil at: 1 > Object: nil error: Invalid value nil: object not indexable > In my Smalltalk, you get a DNU. > In Squeak you get a debugger window with title > Error: instances of UndefinedObject are not indexable > The same for Boolean, Character, and Integer, > except Squeak where (20 factorial at: 1) answers 0 (oh dear oh dear oh dear). > In VW you get a "Subscript out of bounds" error, which is disappointing, > as do true and $a, but a LargePositiveinteger gets #shouldNotImplement. > > > On Tue, 12 Mar 2019 at 15:28, Tim Mackinnon <[hidden email]> wrote: >> >> If you forget to initialise a variable which you thought was a Dictionary - you get a confusing error message: "Error: only integers should be used as indices” if you try an at:put: >> >> This is a consequence of having at:put: defined on Object (which is a bit nasty) >> >> Should UndefinedObject at least override this and signal something a bit more obvious? This is a common and easily done thing and we don't support it very well. >> >> I just did it in some code, and was scratching my head initially until I read the stack properly and realised it was something much simpler than I thought I had done. >> >> Any thoughts on this? > > |
Putting public methods in Object that it cannot honestly support makes #respondsTo: pretty unreliable. It is an obsolete practice, because having Traits means that those methods can be mixed in with (part of) a single line. On Wed, 13 Mar 2019 at 03:20, Ben Coman <[hidden email]> wrote: On Tue, 12 Mar 2019 at 21:56, Marcus Denker <[hidden email]> wrote: |
In reply to this post by Richard O'Keefe
On 12/03/19 9:25 AM, Richard O'Keefe wrote:
> Squeak where (20 factorial at: 1) answers 0 (oh dear oh dear oh > dear). Richard, Could you please elaborate on why this is an error? Large integers are place value encoded (base 256 little endian) and stored in byte arrays, so they need #at:/#at:put: (as private methods). Place value encoding is not architecture-specific so it doesn't affect portability of an image. Regards .. Subbu |
Let's start with portability. I have ST/X, VAST, VW, Squeak, Pharo, GST, Dolphin, and some minor systems. GST and ST/X do not define #at: on any kind of integer at all. Why would they? #basicAt: will do the job, will it not? Dolphin defines #at:[put:] on Integer as self shouldNotImplement and so does VW. In VAST, 20 at: 1 => primitive failed 20 factorial at: 1 => 2192834560 In Squeak and Pharo, 20 at: 1 => not indexable 20 factorial at: 1 => 0 So sending #at: to an integer is not portable between mainstream Smalltalk systems, and for those Smalltalks that define it on large integers, the value is not consistent on the same machine and operating system. But it is worse than that. Maybe you do not care about any Smalltalk but Pharo, and there is a case to be made for that. But this is not consistent with *itself*. 1000000000000 at: 1 fails in a 64-bit VM, where that is a SmallInteger, but answers 0 in a 32-bit VM, where that is a LargePositiveInteger. But it gets *worse*. Numbers are not supposed to be mutable. But in a 32-bit VM, x := 1000000000000. x at: 1 put: 77. x => 1000000000077. I'm sorry, but I had enough grief with constants that weren't in Fortran 66. Again, there isn't the slightest need to define #at:put: on Large...Integers because #basicAt:put: exists. Indeed, we have #{basicAt:,at:,digitAt:}[put:] and surely with #digitAt:[put:] around we can let #at:[put:] be unimplemented on integers? #digitAt: as well. An integer can be viewed as a sequence of bits, right enough, but in a language without silly machine-word limits on integers, it's an *infinite* sequence. At least, if you define logical operations on bignums using a 2s-complement model, a LargePositiveInteger extends infinitely far with 0s and a LargeNegativeInteger extends infinitely far with 1s. GST gets this right. VW gets it right for large positive integers but wrong for large negative ones (or at least works on the absolute value without bothering to explain that). Ah heck, the whole thing is a mess. On Wed, 13 Mar 2019 at 17:18, K K Subbu <[hidden email]> wrote: On 12/03/19 9:25 AM, Richard O'Keefe wrote: |
In reply to this post by K K Subbu
Base 256: that's an implementation detail. Little-endian: that's an implementation detail. My Smalltalk uses base 65536 native-endian and takes some care not to let Smalltalk code find out. (Not least because on 64-bit machines I want to use base 2**32.) For *private* methods, depending on otherwise hidden implementation details is fair enough. My Smalltalk picked up a convention from Squeak -- or rather, from the Squeak mailing list -- that a 'pvt' prefix on a selector makes it truly private and *enforces* that. Pharo does not seem to have anything similar, and #at: is the epitome of a selector in extremely wide general use. Since #digitAt: exists -- and is what the integer classes use -- it is practically certain that #at: is sent to an integer only by mistake. On Wed, 13 Mar 2019 at 17:18, K K Subbu <[hidden email]> wrote: On 12/03/19 9:25 AM, Richard O'Keefe wrote: |
> On 13 Mar 2019, at 08:15, Richard O'Keefe <[hidden email]> wrote: > > My Smalltalk Where can I have a look at that ? |
It's supposed to be on GitHub but I botched it. On Wed, 13 Mar 2019 at 21:08, Sven Van Caekenberghe <[hidden email]> wrote:
|
In reply to this post by Richard O'Keefe
On 13/03/19 12:45 PM, Richard O'Keefe wrote:
> Base 256: that's an implementation detail. > Little-endian: that's an implementation detail. Architecture-specific no. Implementation yes. But that should be fine for private methods. > My Smalltalk uses base 65536 native-endian and > takes some care not to let Smalltalk code find out. > (Not least because on 64-bit machines I want to > use base 2**32.) This would make it host-specific. Byte arrays are not host-specific. > For *private* methods, depending on otherwise > hidden implementation details is fair enough. > My Smalltalk picked up a convention from Squeak > -- or rather, from the Squeak mailing list -- > that a 'pvt' prefix on a selector makes it truly > private and *enforces* that. Pharo does not seem pvt prefix is possibly inspired by Hungarian notation. I find that it impairs readability and maintenance. Should a method change from private to public or vice versa down the line, maintenance will be a nightmare. My own preference is placing them in 'private' category (or even private-* categories). > to have anything similar, and #at: is the epitome > of a selector in extremely wide general use. > Since #digitAt: exists -- and is what the integer > classes use -- it is practically certain that #at: > is sent to an integer only by mistake. You make a good point here. Perhaps #at:/#at:put: should throw an error for all numbers and private methods could use basic versions instead. Regards .. Subbu |
Byte arrays are not host specific. True. But integers are not byte arrays. They don't even contain byte arrays. Just like (boxed) Floats are not word arrays and don't contain word arrays. For what it's worth, I find that it's quite unusual for a method to change from private to public or vice versa. The basic problem with putting methods in a "private" category is that it has no actual effect. It was Smalltalk that taught me OO and the importance of encapsulation. But Smalltalk doesn't actually support encapsulation. Every detail of the implementation of Dictionary, for example, is exposed. And the practice of "self-encapsulation" is actually ANTI-encapsulation for this reason. Now there are several ways to implement hashed collections. The one I've had for years is pleasantly fast and pleasantly free of weird restrictions (keys/elements can be nil and why not). I've got a new one I'm working on that uses less space and is faster still. Because my dialect *enforces* encapsulation, when my testing is complete, I'll be able to swap the new version in, knowing that no external code can possibly depend on the implementation details.obj As a particular example, it was only when I implemented serialisation (nowhere up to Fuel's standards, of course) that I implemented #pvtInstVarAt:[put:] and an object is *still* completely and exclusively in charge of its own instance variables. I agree that using a prefix is not the best way to do this, but the eye soon learns to skip over it. It's not that much worse than "Inst" or "Var" or the pervasive and obtrusive use of prefixes on selectors in VisualAge Smalltalk. I think Pharo would be the better for having *some* way to enforce encapsulation, but what the best way is I don't claim to know. On Wed, 13 Mar 2019 at 21:35, K K Subbu <[hidden email]> wrote: On 13/03/19 12:45 PM, Richard O'Keefe wrote: |
Free forum by Nabble | Edit this page |