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