[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