[Cuis-dev] unnecessary punctuation

Jaromir Matas mail at jaromir.net
Fri Jun 14 05:24:19 PDT 2024


Hi,
My understanding is that this:

 >> [Boris] The meaning of BlockClosure>>value and Association>>value 
have  nothing in common!

is the source of the confusion here; many definitions of #value are not 
"redefinitions" of Object>>value, they are often just simple accessors 
to instance variables called #value.

Do the accessors "spoil the fun"? It's the kind of ("fake") polymorphism 
not available in most languages. Is it good or bad?

And back to the original Mark's question (roughly) - why would it be bad 
to modify the compiler so that

`cond ifTrue: a ifFalse: b`

is treated the same way as

`cond ifTrue: [a] ifFalse: [b]`

i.e. optimized using bytecode jumps rather than sending #ifTrue:ifFalse: 
?

The divergence of b problem would disappear and we'd just have to be 
aware of the different semantics (#value send when used without [ ])...

At any rate the current behavior of #ifTrue:ifFalse: feels inconsistent 
- depending on the "type" of arguments (or the syntactic form).

A side-effect of "legitimizing" this approach would be one could start 
using (or "abusing"?) it like:

a := Association key: 'one' value: 1.
b := Association key: 'two' value: 2.
x := cond ifTrue: a ifFalse: b

and expecting x = 1 or x = 2. Too bad?

Or one could assign blocks to a and b:

a := [1].
b := [2]
x := cond ifTrue: a ifFalse: b

Is it bad to expect  x = 1 or x = 2 ?

I haven't noticed this inconsistency before Mark's question and I'm 
confused now - apologies in case the above doesn't make much sense :)

Best,
Jaromir


On 14-Jun-24 11:16:28 AM, "Boris Shingarov via Cuis-dev" 
<cuis-dev at lists.cuis.st> wrote:

>>  It is *expected* of blocks to understand *#value*. There is no concern; if
>>  you redefine *BlockClosure >> value*, the image will crash.
>
>Not sure what you mean here.  The very first thing we do in PreSmalltalks
>before we begin to build MachineArithmetic, libGDBs etc *is* we
>redefine BlockClosure>>value (to auto-curry when invoked with the wrong
>number of arguments).  I am guessing what you mean is "redefine in a way
>*incompatible* with the live system", but that's a characteristic of
>how liveness is implemented in one particular Smalltalk, not of #value.
>
>>  Right, it’s not a good idea to implement value in Object like this, it
>>  doesnt really generalize anything, I suggest we remove it.
>
>This, on the other hand, *will* break all hell, because now you are
>doing computation in a category without products; and one immediate
>consequence of that, is that Lawvere's elements-as-morphisms no longer
>work.
>
>In more detail:
>
>A (Smalltalk) Object (which we might want to rename to Point or at least
>SetElement if we were really radical) is a morphism from the product of
>zero multiplicands to that (categorical) object.  In other words, it is
>an entity responding to 0-arg #value.  So if I were on a radical course
>to clean-up Object's protocol, #value and #yourself would be the two
>messages I would keep.
>
>>    x := cond ifTrue: a ifFalse: b.
>>
>>  you might be in for a surprise
>
>Yes, exactly that.
>So the problem with the above code is not that it's "twice slower" but
>that it's simply not equivalent to the other one, due to order of
>evaluation.  On the one hand, in Smalltalk-80 there is no easy way to
>tell whether a block/method is a function or a partial function or an
>action; on the other hand, Smalltalk is applicative-order: so what if
>say b diverges?  Then
>
>   1 < 2 ifTrue: [a] ifFalse: [b]
>
>evaluates to ≅a, but
>
>   1 < 2 ifTrue: a ifFalse: b
>
>diverges.  A similar trouble happens when b has a side effect.
>
>>  a surprise if you happen to pass in a or b that implements value
>
>Hmm, yeah, that's an interesting one, let's see:
>
>   x >= 0 ifTrue: a ifFalse: b                  (1)
>
>and let's assume x∈ℤ so x>=0 can't be anything other than a True
>or a False (in unmodified Smalltalk-80 such as vanilla Cuis we don't
>have unsaturated terms, so this works).  So this endows ℤ with a
>simple algebra of types:
>
>   ℤ = ( (ℤ | [ :x | x>=0 ]) + (ℤ | [ :x | x<0 ) )       (2)
>
>so what we are doing in (1) is we are raising to the (2) degree,
>and because (2) is a sum, (1) is a product of A×B (those are types
>of a and b, even though Smalltalk-80 does not provide an explicit
>notation for them).  So we are just precomposing A>>value
>and B>>value before the diagram for ifTrue:ifFalse:, and it HAS
>to go from () to A / to B, and it can ONLY return self (per the
>definition of "element").  Aha!  So I would be inclined to guess
>that we are just looking at plain bogus implementors of #value.
>Let's look what we have in Cuis.  Aha: Association>>value.  Wow.
>I can't think of a better example of what in a conversation some
>time ago on this list we were calling "fake polymorphism".
>The meaning of BlockClosure>>value and Association>>value have
>nothing in common!
>
>... now this got me curious... what other interesting code lurks
>among the implementors of #value...  ha, MessageSend>>value
>special-cases nil arguments vs empty arguments, this smells to
>Lisp's generalized-false, and I wonder if we can normalize that?
>Just for kicks and giggles, let's see where the special-case may be
>used... oh, if I remove it, Cuis dies spectacularly opening a
>million debuggers in WorldMorph>>runLocalStepMethods:...
>would be interesting to probe how deep that rabbit hole goes...
>
>--
>Cuis-dev mailing list
>Cuis-dev at lists.cuis.st
>https://lists.cuis.st/mailman/listinfo/cuis-dev


More information about the Cuis-dev mailing list