Andy/Blair,
I've found myself wanting the above selectors more and more lately so I've just put them back into my image (after an absence of a couple of years). I know that you were having a think about how (and if) to implement in the main image so, to prevent future confusion for me if nothing else, I was wondering if you had reached any sort of conclusion. FWIW, my #ifNotNil takes the receiver as an argument (seems a bit pointless not to) Ian |
[hidden email] (Ian Bartholomew) wrote (abridged):
> FWIW, my #ifNotNil takes the receiver as an argument (seems a bit > pointless not to) So #ifNotNil: takes an argument and #ifNil: doesn't? The asymmetry makes me feel a bit uncomfortable. Then again, #ifNotNil: really needs that argument sometimes, and with #ifNil: the argument will always be nil (duh!) so there is no point. The QKS version of Smalltalk does not require the number of arguments supplied to match the number expected by a block. Extra arguments are discarded, missing ones are supplied as nil by the system. This works nicely with #ifNil:/#ifNotNil: - methods can take an argument or not, as it suits them. This is the only solution I've seen which really strikes me, but adopting it in Dolphin would be a more radical change than adding a couple of methods. Dave Harris, Nottingham, UK | "Weave a circle round him thrice, [hidden email] | And close your eyes with holy dread, | For he on honey dew hath fed http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
Dave,
> So #ifNotNil: takes an argument and #ifNil: doesn't? > > The asymmetry makes me feel a bit uncomfortable. Then again, #ifNotNil: > really needs that argument sometimes, and with #ifNil: the argument will > always be nil (duh!) so there is no point. I think the asymmetry is the only reason why the construct hasn't become an standard part of the Smalltalk syntax. It does feel like it should match the ifTrue/ifFalse format and that you should be able to exchange the blocks at will. Another way of implementing them, that might help with the uncomfortable feeling, is to remove the implied syntactic link and just treat it as four separate methods. Something like (and I don't really like these but can't think of anything better at the moment) - ifNil: [] ifNil: [] ifNot: [:arg | ] ifDefined: [:arg | ] ifDefined: [:arg | ] ifNot: [] but I'm not sure you actually gain much by doing this. I have to say though that the first time I used it in anger, after putting it back into my image, I forgot the block argument! <sigh> Ian |
In reply to this post by Ian Bartholomew
Ian,
> FWIW, my #ifNotNil takes the receiver as an argument (seems a bit pointless > not to) I've never used the #ifNil* family since all my significant Smalltalk has been in Dolphin, so this is just a random rant from an uniformed observer... Still, misc observations, in no special order: Block arguments that I almost never use drive me nuts. I'd rather have the convenience of not having the block argument, and use a different expression in the handfull of cases where I would have wanted it. (I'm reminded of the convention that #at:put:, etc, answer the added object -- this is useful (but not necessary) on about 2% of occasions, and is just a nuisance on the other %98). I don't think the selector is especially nice. If #ifNil: answers the result of the block, so that myVar := otherVar ifNil: [23]. is usefull, then I'd suggest that a better name is #orIfNil: Maybe you don't agree, and it's certainly not "standard", but I think it reads better as: myVar := otherVar orIfNil: [23]. Similarly, to my mind, #ifNil:else: reads better than #ifNil:ifNot:. > Ian -- chris |
In reply to this post by Ian Bartholomew
Construction like "ifNil / ifNotNil" may be useful in lazy initialization.
Classical example: MyObject>>foo foo isNil ifTrue: [ foo := self newFoo ]. ^ foo If I could write: MyObject>>foo ^ foo ifNilBecome: self newFoo it would be more clear in syntax ( and typing :-) but, I dont see a straight way for realization... Dmitry Zamotkin "Ian Bartholomew" <[hidden email]> wrote in message news:JmPH6.22893$[hidden email]... > Andy/Blair, > > I've found myself wanting the above selectors more and more lately so I've > just put them back into my image (after an absence of a couple of years). I > know that you were having a think about how (and if) to implement in the > main image so, to prevent future confusion for me if nothing else, I was > wondering if you had reached any sort of conclusion. > > FWIW, my #ifNotNil takes the receiver as an argument (seems a bit pointless > not to) > > Ian > > > > > > |
In reply to this post by Chris Uppal-3
Chris,
> Block arguments that I almost never use drive me nuts. I'd rather have > the convenience of not having the block argument, and use a different > expression in the handfull of cases where I would have wanted it. Yes, that would be an option. It fits in with what I said yesterday about removing the coupling between ifNil and ifNotNil and just treating them as 4, or 6, separate-but-related method definitions. > I don't think the selector is especially nice. No, neither do I. It's default to find something general enough to replace it though > Similarly, to my mind, #ifNil:else: reads better than #ifNil:ifNot:. I was trying to match things like #detect:ifNone: and #at:ifAbsent:. Perhaps #ifNil:butIfNot: ... or perhaps not <g> I suppose the other question is whether it is worth it at all?. I've been trying to think of occasions where it would make a difference to existing code, make it more readable or more efficient, and came up with the following generalisations - I'm sure there are more but I can't think of them offhand (anyone?) x * (y ifNil: [1]) or x * (y ifNil: [y := 1]) or x * (y := y ifNil: [1]) (avoids a separate test to set var) x := FileOpenDialog showModal ifNil: [^self] ifNotNil: [:arg | FileStream read: arg] (avoids an extra var) ^x := x ifNil: [123] (lazy initialisation) assuming Object>>isNil and UndefinedObject>>ifNotNil both answer the receiver and the others answer the block value. What's the general feeling. Does ifNil/ifNotNil add anything or is it just a waste of image space? Ian |
In reply to this post by Chris Uppal-3
I wrote:
> so this is just a random rant from an uniformed observer... Urk! That should be "uninformed", I haven't worn a uniform since my school days... -- chris |
In reply to this post by Ian Bartholomew
Ian,
> > Block arguments that I almost never use drive me nuts. I'd rather have > > the convenience of not having the block argument, and use a different > > expression in the handfull of cases where I would have wanted it. > > Yes, that would be an option. It fits in with what I said yesterday about > removing the coupling between ifNil and ifNotNil and just treating them as > 4, or 6, separate-but-related method definitions. I don't think I expressed myself very clearly? I meant that even though the argument to #ifNotNil:'s block would be useful sometimes, I didn't think it'd be useful enough to "earn" the brainspace it'd take up. I'd rather not have it, and code around the cases where it would have been useful, than have it and have to remember about it even when I didn't need it. Actually, having thought about it a bit more, I'm not too sure about that anymore. In any case I think that the biggest gain would be improved compatibility with other Smalltalks, rather than greater ease of expression for myself, so I think the important thing is to do what the other Smalltalks do. I remember that Blair said there was an issue with which version of #IfNil: (etc) to be compatible *with*, but I can't remember the details. VW doesn't seem to have the #ifNil family, so I suppose it's a choice between Squeak or VAST compatibility (that's just a guess -- I've never even seen VAST). If so then maybe a good way to get a handle on which route is best is to ask on c.l.s what the VW users have found it expedient to do. > I suppose the other question is whether it is worth it at all?. I've been > trying to think of occasions where it would make a difference to existing > code, make it more readable or more efficient, [..] I don't think it'd *ever* be more efficient -- at least not unless the compiler recognised it as a special form to be inlined (which I think I'd oppose). OTOH a *large* number of expressions in the image could be made slightly more elegant. But, for myself, I don't think I'd use them much. The existing form is perfectly transparent, so I can't really imagine myself choosing to use the shorter form when I know that it's (microscopically) slower. I'm not really such an efficiency nut as that makes it sound; the way I see it is that I'd have a choice: (1) Make a rule, always to use the elegant form and never think about efficiency. (2) Make a rule, always to use the efficient form. (3) Stop and think each time I use #isNil to decide whether to go for elegance or speed. Choice (3) would be kind of stupid, so it comes down to (1) or (2). I find (1) a bit dubious, so I think I'd end up making (2) my rule. (Also, if I did go with (1) then I'd be *massively* bugged by all my existing code which still used the old form -- people tell me I'm odd...) So, for me, the actual gain would only be increased easy of porting code from Squeak (or similar). > What's the general feeling. Does ifNil/ifNotNil add anything or is it just a > waste of image space? On the whole, I think they'd be worth the space. > Ian -- chris |
[hidden email] (Chris Uppal) wrote
(abridged): > I don't think I expressed myself very clearly? I meant that even > though the argument to #ifNotNil:'s block would be useful sometimes, > I didn't think it'd be useful enough to "earn" the brainspace it'd > take up. I'd rather not have it, and code around the cases where > it would have been useful, than have it and have to remember about > it even when I didn't need it. If it doesn't take an argument, I don't see much advantage from using it. Compare: |value| value := anObject someMessage. value notNil ifTrue: [value someOtherMessage]. versus: |value| value := anObject someMessage. value ifNotNiL: [value someOtherMessage]. versus: |value| (value := anObject someMessage) ifNotNiL: [ value someOtherMessage]. versus: anObject someMessage ifNotNiL: [:value| value someOtherMessage]. I don't think the second had much advantage over the first. The third is a bit shorter but only at the cost of introducing brackets and general complication. The last does seem genuinely clearer to me, because it avoids having to name and declare the temporary variable at the top of the method. The variable's scope is smaller and it has its correct, non-nil value for all of it. To put it another way, there is no mutable state, no destructive assignment. > (1) Make a rule, always to use the elegant form and never think > about efficiency. > (2) Make a rule, always to use the efficient form. > (3) Stop and think each time I use #isNil to decide whether to go > for elegance or speed. > > Choice (3) would be kind of stupid, so it comes down to (1) or (2). I > find (1) a bit dubious, so I think I'd end up making (2) my rule. I'd go for: (4) Use the elegant form unless there is a pressing concern about speed. This is similar to (3), except that "Stop and think each time" gives the wrong impression. I've found the #ifNotNil: pattern above to be rarer than the lazy initialisation one. There are lots of different ways to do lazy initialisation, and I would much prefer to settle on one canonical form. Having a specific message may encourage that. Dave Harris, Nottingham, UK | "Weave a circle round him thrice, [hidden email] | And close your eyes with holy dread, | For he on honey dew hath fed http://www.bhresearch.co.uk/ | And drunk the milk of Paradise." |
Just to chime in my two bits...
-- Dave S. [SmallScript, QKS Smalltalk/SmalltalkAgents] ============================== Recap of the arg/no-arg design issue: ------------------------------------ If we were designing this for smalltalk dialects that require block #value... messages to have parity with the number of arguments declared in a block, we must decide on the number of arguments (0 or 1) for the various message forms. singular forms: --------------- ifNil: nilValuable ifNotNil: notNilValuable combinatoric forms: ------------------ ifNil: ... ifNotNil: ... ifNotNil: ... ifNil: ... Where the protocol for <Block> instances would be: notNilValuable --> [:nonNilValue| "arg required"] nilValuable --> ["no arg provided"] ----- These forms have proven to be a very useful construct in QKS Smalltalk since I added it to the core frameworks ~1992. There was a lot of comp.lang.smalltalk debate on these forms because until 1995, (for these messages and #isNil,#notNil) our Smalltalk implementation of these methods treated <0> and <nil> the same way. In 1995 I swept the QKS Smalltalk image and updated it, at which point we removed the <0> support; at which time a new set of messages #ifZero:, #ifNotZero:,... was added. Around 1994, one of our users wanted an even shorter (binary message) form for some common usage operations. They had defined #? to be the same as #ifNil:. I really liked that #? variant and added it, as well as defining a #!? variation, to our base image ~1994. They have proven to be really attractive and I find myself using them often. So, this leads to: ? nilValuable !? notNilValuable I.e., the messages #? and #ifNil: do the exact same thing; and similarly for #!? and #ifNotNil:. I'm assuming the reader recognizes that contract for the #(? !? ifNil: ifNotNil: ...) forms is based on #value... messages (<IValuable> protocol). ----- The SmallScript and QKS Smalltalk compilers have always inlined all the original forms, and when I added core image support for #?, #!?, #ifZero:, ... they too became inlined forms. An astute reader will readily observe that inlining is never an issue because the <nil> messages apply to every object/class with a uniform meaning -- special inlining is done for the zero forms (compiler actually sends the message #isZero for its testing). Some patterns of use: -------------------- method [ foobar ^foobar ? [foobar := ...init-expr...] ]. method [ messageName "" This pattern is especially useful in various "" looping/control-flow situations expr use: (expr ? [^nil]) doSomethingExpr ]. ---- It is also convenient if your ST-IDE/editor supports keybindings for editing operations like: - parenQuoteSelectorOrRestOfLine (...) - blockQuoteSelectorOrRestOfLine [...] In our editors, hitting ctl-( will parenQuote the current selection, or if none, the text from the caret position to the last non-whitespace in the line. Similar for various other quote forms ctl-[, ctl-', ctl-", etc. |
"Paolo Bonzini" <[hidden email]> wrote in message
news:[hidden email]... > > Around 1994, one of our users wanted an even shorter (binary > > message) form for some common usage operations. They had > > defined #? to be the same as #ifNil:. > > This is not good in my opinion. One is free to define binary selector > for whatever they like, but when you add them to Object you *must* > expect clashes! > > For example, GNU Smalltalk's i18n library uses #? as a shortcut > for #print: so that you can do things like > > "nls is an instance of LcMessagesDomain" > nls ? 'a string to be translated' > > myLcMonetary ? 123456 > LcTime posix ? DateTime now > LcNumeric default ? 123456 > > but they are implemented in the Locale class! > > For this reason I am against adding arbitrary binary > selectors to Object, and much more against inlining! Interesting. First, let me be clear that there is nothing "arbitrary" about the SmallScript or QKS use of the #? and #!? selectors; noting they've been in our images (as described) for some 7 years. Having done a simple scan of use in our various tools and libraries, there are literally thousands of methods that use these forms. So it is certainly a very useful and quickly recognized pattern. However, that rationale aside, SmallScript is explicitly designed to support multi-methods and scoped messaging operations to reduce selector name clashing. Thus, given its design philosphy, SmallScript should be able to support both the <nil> form and locale-usage definitions, you've described, without a problem. "" Here is a sample of such method declarations method behavior: ILocale [ ? <String> aString ... ]. method behavior: ILocale [ ? <Time> aTime ... ]. method behavior: ILocale [ ? <Number> aNumber ... ]. ---- SIDEBAR on I18N/Locale stuff ---- This commentary is specific to globalization I18N related work, and, in general terms, has nothing to do with the basic issue of selector name clashes brought up by the preceding poster (Paolo). --- I've done very extensive work in the area of globalization/internationalization/localization (incl. japanization) on all the major OS platform groups over the last 14 years, have quite a few friends in this field, and have served on the LI18NUX standards group as well. So, from that vantage point, I think that using #?, while certainly convenient as a terse binary message, it is not particularly intuitive and in-and-of-itself insufficient for serious locale work. In looking for a terse "binary-message" mapping selector for this GNU usage pattern I might have chosen something from one of these lists: <= <<= Which suggests a flow of the data through a (stream-like) locale transformation/presentation filter. stdout cr << (locale <= 'literal'). However, in a convenience scenario, I would have expected all the user/local/policy configuration and settings to be part of the thread local state/variables/configuration. Thus a more convenient forms might be: #(localize localeForm asLocalForm ...) "" Thus our short form, a really convenient unary selector, "" might be. stdout cr << 'literal' localize. ---- END SIDEBAR ---- Based on the actual use pattern of #? and #!? I just spent five minutes and modified the inline mechanism in SmallScript to only perform inlining for the multi-method variant of "<any> ? <Block>". (** its taken me far longer to write this post ** :) With that change inline optimization still covers 99.9% of the actual use cases of #? while leaving the selector free and clear for almost any other purpose. ** and at some level, this pattern could be recognized and optimized soley at the JIT layer -- it's just simpler for the compiler to inline the block forms ** An arbitrary package or module is free to define any other variants. I.e., the #? and #!? for the 99% usage case will be inlined and optimized *and* the GNU locale code would compile and work in SmallScript (Smalltalk) without conflict/problems. I should also comment that single-character binary selectors (and even common two symbol ones) should be used judiciously when designing a wholly "new semantic" for them within a framework. All prior issues aside, their (binary selectors) very terse convenience also means that they may well not be "self revealing" as to their intent. As a result, if their intent is not "common/universal", or "obvious" within their context of use; then they are probably a poor choice. In that circumstance, if binary selectors are really desireable/needed, a more esoteric combination should be used to avoid confusion among diverse semantic applications of said selectors. --- I should also point out that in QKS Smalltalk, we have consistently use the binary selector character $!, to represent the "not" case of any related binary message pattern. We have also tried to choose binary message patterns that corresponded to "popular" use of similar messages/operators in the mainstream of "programming languages". Thus: = vs != "" The ~= pattern is deprecated (not recognized in the mainstream) == vs !== "" The ~~ pattern is deprecated (not recognized in the mainstream) ? vs !? And, for prefix selector forms {+,-,~,!} !expr "" Compiler generates as: "expr not" Our frameworks support various deprecated (or multi-dialect conflicting) message forms. Our AOS Platform virtual machine technology and object model provide the ability to alias selectors. This aliasing is used to efficiently and consistently treat deprecated forms as if they were the preferred form in all behavioral circumstances. -- Dave S. [SmallScript; QKS Smalltalk/SmalltalkAgents] > > Paolo > > > -- > Posted from relay3.inwind.it [212.141.53.74] > via Mailgate.ORG Server - http://www.Mailgate.ORG |
In article <9dHJ6.43101$[hidden email]>,
David Simmons <[hidden email]> wrote: | Based on the actual use pattern of #? and #!? I just spent five minutes and | modified the inline mechanism in SmallScript to only perform inlining for | the multi-method variant of "<any> ? <Block>". (** its taken me far longer | to write this post ** :) Dave, when you mention inlining here, do you mean that the compiler avoids building block instances and sending #value to them, and instead it generates VM codes for the expressions (inline) with jumps/gotos around the if/else portions? Regards, Kevin -- Kevin Szabo ---- "I am Fudd of Borg. Wesistance is usewess!" |
"Kevin Szabo" <[hidden email]> wrote in message
news:9daqal$48k$[hidden email]... > In article <9dHJ6.43101$[hidden email]>, > David Simmons <[hidden email]> wrote: > | Based on the actual use pattern of #? and #!? I just spent five minutes and > | modified the inline mechanism in SmallScript to only perform inlining for > | the multi-method variant of "<any> ? <Block>". (** its taken me far longer > | to write this post ** :) > > Dave, when you mention inlining here, do you mean that the compiler > avoids building block instances and sending #value to them, and instead > it generates VM codes for the expressions (inline) with jumps/gotos > around the if/else portions? Simple answer: ------------- Yup. More Detail: (about what happens if a block is not inlined) ----------- The language level compiler only builds block instances for "static/literal" (clean) blocks; which it stores in a method's literals. For which it emits a load-static-block opcode which includes the branch lable for skipping to the end of the opcodes for the block. ---- Blocks that require per/block-instance reference to some form of contextual (instantiation-context) state must be created at execution time. For blocks that must be instantiated (created) at execution time, the language level compiler emits a load-new-block opcode which includes the branch label for skipping to the end of the opcodes for the block. As the JIT's analyzer examines methods and their opcodes, it determines all the remaining characteristics of a "non-static/non-literal" (dirty) block on the fly. Hence, the reason why I suggested in some post or other that the JIT could actual handle the inlining directly by avoiding the actual creation and loading of a new-block and subsequent #value... message. It was just easier to have the language compiler do it. -- Dave S. [www.smallscript.net; QKS Smalltalk/SmalltalkAgents] > > Regards, > Kevin > -- > Kevin Szabo ---- "I am Fudd of Borg. Wesistance is usewess!" |
Free forum by Nabble | Edit this page |