What to believe?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

What to believe?

Piers Cawley
What is a young Smalltalker to do? SmallLint forcefully suggests that:

^ Preferences optionalButtons
    ifTrue: [OBFixedButtonPanel new]

should be rewritten as:

^ Preferences optionalButtons
    ifTrue: [OBFixedButtonPanel new]
    ifFalse: [nil]

which would be fine, but as soon as I try and pretty print the
rejigged method, it reverts to the version without the ifFalse:
clause?

Two tools enter, one tool leaves. But which one?

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Blake-5
On Tue, 26 Jun 2007 13:24:39 -0700, Piers Cawley <[hidden email]>  
wrote:

> What is a young Smalltalker to do? SmallLint forcefully suggests that:
>
> ^ Preferences optionalButtons
>     ifTrue: [OBFixedButtonPanel new]
>
> should be rewritten as:
>
> ^ Preferences optionalButtons
>     ifTrue: [OBFixedButtonPanel new]
>     ifFalse: [nil]
>
> which would be fine, but as soon as I try and pretty print the
> rejigged method, it reverts to the version without the ifFalse:
> clause?

The latter strikes me as silly. In a language where "if" is part of the  
grammar, I can see it sort-of making sense, especially if nesting "if"s,  
to include "else"s with NOPs.




Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Jon Hylands
On Tue, 26 Jun 2007 13:45:22 -0700, Blake <[hidden email]> wrote:

> The latter strikes me as silly. In a language where "if" is part of the  
> grammar, I can see it sort-of making sense, especially if nesting "if"s,  
> to include "else"s with NOPs.

The issue is, what does the expression return, in the false case, if
#ifFalse: isn't there?

It may be a Smalltalk standard to return nil in that case - I have no idea.
Personally, when I'm doing something with an expression (like returning it,
or assigning it), I always make it very explicit what I (the programmer)
expect to happen in all cases...

Later,
Jon

--------------------------------------------------------------
   Jon Hylands      [hidden email]      http://www.huv.com/jon

  Project: Micro Raptor (Small Biped Velociraptor Robot)
           http://www.huv.com/blog

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Blake-5
On Tue, 26 Jun 2007 14:00:36 -0700, Jon Hylands <[hidden email]> wrote:

> On Tue, 26 Jun 2007 13:45:22 -0700, Blake <[hidden email]> wrote:
>
>> The latter strikes me as silly. In a language where "if" is part of the
>> grammar, I can see it sort-of making sense, especially if nesting "if"s,
>> to include "else"s with NOPs.
>
> The issue is, what does the expression return, in the false case, if
> #ifFalse: isn't there?
>
> It may be a Smalltalk standard to return nil in that case - I have no  
> idea. Personally, when I'm doing something with an expression (like  
> returning it, or assigning it), I always make it very explicit what I  
> (the programmer)
> expect to happen in all cases...

Good point. I didn't note the ^ at the beginning and was just looking at  
the statment.

However, is the question not really "What do the booleans return from an  
if* statement if the conditional is not met"? In which case, the answer is  
"nil".

Which, perhaps inevitably, leads me back to my original conclusion: It's  
silly. "if" is not a language construct with undefined and potentially  
ambiguous results. It's a set of messages sent to a class. It's kind of  
like all those languages that use "for" loops in which the control  
variable is undefined after the loop. Lint tools will warn you about using  
that control variable; that would just be silly in Smalltalk.

I guess if we're talking portability though, it might be a valid question.  
I'm not sure the Smalltalk spec mandates that instances of True and False  
must return nil. But what else =would= they return? Self?

        ===Blake===

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Bert Freudenberg
On Jun 26, 2007, at 23:59 , Blake wrote:

> However, is the question not really "What do the booleans return  
> from an if* statement if the conditional is not met"? In which  
> case, the answer is "nil".
>
> I guess if we're talking portability though, it might be a valid  
> question. I'm not sure the Smalltalk spec mandates that instances  
> of True and False must return nil.

"ifTrue: aBlock" is short-hand for "ifTrue: trueBlock ifFalse: []".  
The value of an empty block is nil by definition. That's why True and  
False must return nil in #ifFalse: and #ifTrue:, respectively.

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Andreas.Raab
Bert Freudenberg wrote:
>> I guess if we're talking portability though, it might be a valid
>> question. I'm not sure the Smalltalk spec mandates that instances of
>> True and False must return nil.
>
> "ifTrue: aBlock" is short-hand for "ifTrue: trueBlock ifFalse: []". The
> value of an empty block is nil by definition. That's why True and False
> must return nil in #ifFalse: and #ifTrue:, respectively.

That is not necessarily the case. One can make an equally good argument
saying that "foo ifTrue:[...]" should expand to "foo ifTrue:[...]
ifFalse:[foo]" which is coincidentally true for ifNil:ifNotNil: and
*should* be true (and I'm glad we fixed this in Croquet) for
ifEmpty:ifNotEmpty:. In other words if it is the case that:

   42 ifNil:[...] => 42
   #(1 2 3) ifEmpty:[...] => #(1 2 3)

then it seems quite consistent to have

   false ifTrue:[...] => false.

(not that I'm proposing to change this btw, since it would break a whole
bunch of stuff but it's perfectly consistent with other semantics that
are generally deemed "intuitive")

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Blake-5
In reply to this post by Bert Freudenberg
On Tue, 26 Jun 2007 23:54:39 -0700, Bert Freudenberg  
<[hidden email]> wrote:

> "ifTrue: aBlock" is short-hand for "ifTrue: trueBlock ifFalse: []". The  
> value of an empty block is nil by definition. That's why True and False  
> must return nil in #ifFalse: and #ifTrue:, respectively.

So, lint is in this case un-short-handing.




Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Bert Freudenberg
In reply to this post by Andreas.Raab

On Jun 27, 2007, at 9:02 , Andreas Raab wrote:

> Bert Freudenberg wrote:
>>> I guess if we're talking portability though, it might be a valid  
>>> question. I'm not sure the Smalltalk spec mandates that instances  
>>> of True and False must return nil.
>> "ifTrue: aBlock" is short-hand for "ifTrue: trueBlock ifFalse:  
>> []". The value of an empty block is nil by definition. That's why  
>> True and False must return nil in #ifFalse: and #ifTrue:,  
>> respectively.
>
> That is not necessarily the case. One can make an equally good  
> argument saying that "foo ifTrue:[...]" should expand to "foo  
> ifTrue:[...] ifFalse:[foo]" which is coincidentally true for  
> ifNil:ifNotNil: and *should* be true (and I'm glad we fixed this in  
> Croquet) for ifEmpty:ifNotEmpty:. In other words if it is the case  
> that:
>
>   42 ifNil:[...] => 42
>   #(1 2 3) ifEmpty:[...] => #(1 2 3)
>
> then it seems quite consistent to have
>
>   false ifTrue:[...] => false.
>
> (not that I'm proposing to change this btw, since it would break a  
> whole bunch of stuff but it's perfectly consistent with other  
> semantics that are generally deemed "intuitive")

Granted. I understood the question to be about wether the behavior  
was arbitrary and Squeak-specific or actually specified and portable.  
I'd argue it's the latter, if only because ifTrue:/ifFalse: predates  
the other constructs by a large margin and all Smalltalk variants  
inherited that behavior.

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Blake-5
In reply to this post by Andreas.Raab
On Wed, 27 Jun 2007 00:02:46 -0700, Andreas Raab <[hidden email]>  
wrote:

> ifEmpty:ifNotEmpty:. In other words if it is the case that:
>
>    42 ifNil:[...] => 42
>    #(1 2 3) ifEmpty:[...] => #(1 2 3)
>
> then it seems quite consistent to have
>
>    false ifTrue:[...] => false.
>
> (not that I'm proposing to change this btw, since it would break a whole  
> bunch of stuff but it's perfectly consistent with other semantics that  
> are generally deemed "intuitive")

Given that we're off in alternate realities, this probably isn't that  
important but wouldn't the above require a lot of code like this to be  
written:

^someTest ifTrue:[someObject] ifFalse: [nil].

because otherwise the return value will be a valid non-nil object that  
must be tested for. In other words, unless you set the result to nil  
specifically, clients of the code must be prepared to handle a valid  
object, nil (as now), and a boolean. And they must have awareness of the  
fact that sometimes True means nil and sometimes False means nil (or I  
guess that a boolean means nil). And then what if the non-nil block  
returns a boolean?

Not that such would be insurmountable, but it seems like the approach as  
implemented is cleaner.

        ===Blake===

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Bert Freudenberg
In reply to this post by Blake-5

On Jun 27, 2007, at 9:14 , Blake wrote:

> On Tue, 26 Jun 2007 23:54:39 -0700, Bert Freudenberg  
> <[hidden email]> wrote:
>
>> "ifTrue: aBlock" is short-hand for "ifTrue: trueBlock ifFalse:  
>> []". The value of an empty block is nil by definition. That's why  
>> True and False must return nil in #ifFalse: and #ifTrue:,  
>> respectively.
>
> So, lint is in this case un-short-handing.

Right. As Andreas points out it is conceivable that some Smalltalk  
would redefine the meaning so this would be more portable, and it  
might be considered more readable because it spells out the other  
case explicitly, leaving no one to wonder about the return value.

- Bert -



Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Blake-5
In reply to this post by Blake-5
On Wed, 27 Jun 2007 00:26:55 -0700, Blake <[hidden email]> wrote:

>
> Given that we're off in alternate realities, this probably isn't that  
> important but wouldn't the above require a lot of code like this to be  
> written:
>
> ^someTest ifTrue:[someObject] ifFalse: [nil].

Which, I guess, now that Bert re-points it out, is exactly where we  
started.

Heh.

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Alexander Lazarevic'
In reply to this post by Andreas.Raab
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andreas Raab schrieb:
> That is not necessarily the case. One can make an equally good argument
> saying that "foo ifTrue:[...]" should expand to "foo ifTrue:[...]
> ifFalse:[foo]" which is coincidentally true for ifNil:ifNotNil: and
> *should* be true (and I'm glad we fixed this in Croquet) for
> ifEmpty:ifNotEmpty:. In other words if it is the case that:
>
>   42 ifNil:[...] => 42
>   #(1 2 3) ifEmpty:[...] => #(1 2 3)

I had above expectation for ifEmpty: once and got so badly burned, that
I chickened out of using ifNil:, ifEmtpy: and their homies completely.

Alex
-----BEGIN PGP SIGNATURE-----
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFGgjkhYiF2wSTEZ9gRAiK6AKD12y8htqds/V80+rQmNUKFoRtbwACfdE3K
GLrgsovXUVA2/PKaG8tlHZI=
=2lRB
-----END PGP SIGNATURE-----

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

stephane ducasse
In reply to this post by Andreas.Raab
Hi andreas

> That is not necessarily the case. One can make an equally good  
> argument saying that "foo ifTrue:[...]" should expand to "foo  
> ifTrue:[...] ifFalse:[foo]" which is coincidentally true for  
> ifNil:ifNotNil: and *should* be true (and I'm glad we fixed this in  
> Croquet) for ifEmpty:ifNotEmpty:. In other words if it is the case  
> that:
>
>   42 ifNil:[...] => 42
>   #(1 2 3) ifEmpty:[...] => #(1 2 3)
>

Can you elaborate more on why it should be true for ifEmpty:?

> then it seems quite consistent to have
>
>   false ifTrue:[...] => false.
>
> (not that I'm proposing to change this btw, since it would break a  
> whole bunch of stuff but it's perfectly consistent with other  
> semantics that are generally deemed "intuitive")
>
> Cheers,
>   - Andreas
>
>


Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Dan Ingalls
In reply to this post by Bert Freudenberg
>On Jun 27, 2007, at 9:14 , Blake wrote:
>
>>On Tue, 26 Jun 2007 23:54:39 -0700, Bert Freudenberg <[hidden email]> wrote:
>>
>>>"ifTrue: aBlock" is short-hand for "ifTrue: trueBlock ifFalse: []". The value of an empty block is nil by definition. That's why True and False must return nil in #ifFalse: and #ifTrue:, respectively.
>>
>>So, lint is in this case un-short-handing.
>
>Right. As Andreas points out it is conceivable that some Smalltalk would redefine the meaning so this would be more portable, and it might be considered more readable because it spells out the other case explicitly, leaving no one to wonder about the return value.

I may be the one responsible for the shorthand here (but memory does not serve in this case).  In any event, I'll add that I agree with the lint point of view that any of these paired expressions should include the nil branch when evaluated for value (as in assignments, as arguments, and as return values).  The decompiler can recognize these cases, so I'd certainly agree with modifying the decompiler accordingly.  When only evaluated for effect, the shorthand is not only simpler, but it invariably matches the program as originally written, so that should be retained.

        - Dan

Reply | Threaded
Open this post in threaded view
|

Re: What to believe?

Chris Muller-3
In reply to this post by Piers Cawley
Someone wrote a package where you could allow specific "violations"
for specific methods declared (I think) on the class side so that Lint
would then ignore it going foward.

I can't remember who did it, but it was in the last few years.  You'd
have to search the archives to find it..

On 6/26/07, Piers Cawley <[hidden email]> wrote:

> What is a young Smalltalker to do? SmallLint forcefully suggests that:
>
> ^ Preferences optionalButtons
>     ifTrue: [OBFixedButtonPanel new]
>
> should be rewritten as:
>
> ^ Preferences optionalButtons
>     ifTrue: [OBFixedButtonPanel new]
>     ifFalse: [nil]
>
> which would be fine, but as soon as I try and pretty print the
> rejigged method, it reverts to the version without the ifFalse:
> clause?
>
> Two tools enter, one tool leaves. But which one?
>
>