[Cuis-dev] unnecessary punctuation

Boris Shingarov shingarov at labware.com
Fri Jun 14 02:16:28 PDT 2024


> 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...



More information about the Cuis-dev mailing list