printing literals exactly (was isSelfEvaluating)

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

printing literals exactly (was isSelfEvaluating)

Nicolas Cellier
2009/10/31 Nicolas Cellier <[hidden email]>:

> 2009/10/31 Stéphane Rollandin <[hidden email]>:
>>>> If the meaning of #isLiteral is to indicate that what is printed can be
>>>> read back (i.e. will be correctly parsed) then I think it is a very useful
>>>> message that we should keep.
>>>
>>> #isLiteral mainly indicates which objects can be created at compile time.
>>> They are literally inserted in the compiled method. This must match the
>>> syntax definition of Squeak. There is no question about not keeping it.
>>
>> now I'm confused. are all objects anwering true to #isLiteral also have a
>> printed form that can be read back ? should they ?
>>
>> Stef
>>
>
> I think this is used as a feature at least in Decompiler.
>
> But can they all be read back ?
> Float can't always with the current implementation (they don't print exactly).
>
> (Compiler evaluate: Float halfPi printString) = Float halfPi
>
> Nicolas
>

By the way, there is a workaround in CompiledMethod>>#=

self isFloat ifTrue: [...]

The #halt: in there sounds like calling for a better fix.
For example, the workaround does not work with a literal Array of Float...

Nor does it deal with infinity:
(Float class compile: (Float class >> #initialize) decompileString
                classified: nil
                notifying: requestor
                trailer: Float class defaultMethodTrailer
                ifFail: [^nil]) method = (Float class >> #initialize)

We have an excellent absPrintExactlyOn:base: that avoids extra digits
when unnecessary...
...but it is 3x to 10x slower and nobody dared generalizing its usage.

{0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
0.1 . 237.128} collect: [:e |
        [String streamContents: [:s | e absPrintExactlyOn: s base: 10]] bench
        ->[String streamContents: [:s | e printOn: s base: 10]] bench]

{'12131.77364527095 per second.'->'63358.65653738505 per second.'.
'1535.292941411718 per second.'->'6756.64867026595 per second.'.
'653.669266146771 per second.'->'6667.066586682664 per second.'.
'1004.199160167966 per second.'->'5857.82843431314 per second.'.
'8732.85342931414 per second.'->'26025.3949210158 per second.'.
'8635.87282543491 per second.'->'19715.45690861827 per second.'.
'2666.26674665067 per second.'->'13040.99180163967 per second.'}

Nicolas

Reply | Threaded
Open this post in threaded view
|

Re: printing literals exactly (was isSelfEvaluating)

Nicolas Cellier
Hehe, I've got a plan.

Use storeOn: rather than printOn: to produce the decompileString.
It will be the same for all literals, but Float in which I will
override storeOn:

My plan is to print exactly if isFinite, or invoke a message pattern
otherwise (Float nan, Float infinity, Float infinity negated).
Note that these exceptional values are not literals (I already fixed that).

Nicolas

2009/10/31 Nicolas Cellier <[hidden email]>:

> 2009/10/31 Nicolas Cellier <[hidden email]>:
>> 2009/10/31 Stéphane Rollandin <[hidden email]>:
>>>>> If the meaning of #isLiteral is to indicate that what is printed can be
>>>>> read back (i.e. will be correctly parsed) then I think it is a very useful
>>>>> message that we should keep.
>>>>
>>>> #isLiteral mainly indicates which objects can be created at compile time.
>>>> They are literally inserted in the compiled method. This must match the
>>>> syntax definition of Squeak. There is no question about not keeping it.
>>>
>>> now I'm confused. are all objects anwering true to #isLiteral also have a
>>> printed form that can be read back ? should they ?
>>>
>>> Stef
>>>
>>
>> I think this is used as a feature at least in Decompiler.
>>
>> But can they all be read back ?
>> Float can't always with the current implementation (they don't print exactly).
>>
>> (Compiler evaluate: Float halfPi printString) = Float halfPi
>>
>> Nicolas
>>
>
> By the way, there is a workaround in CompiledMethod>>#=
>
> self isFloat ifTrue: [...]
>
> The #halt: in there sounds like calling for a better fix.
> For example, the workaround does not work with a literal Array of Float...
>
> Nor does it deal with infinity:
> (Float class compile: (Float class >> #initialize) decompileString
>                classified: nil
>                notifying: requestor
>                trailer: Float class defaultMethodTrailer
>                ifFail: [^nil]) method = (Float class >> #initialize)
>
> We have an excellent absPrintExactlyOn:base: that avoids extra digits
> when unnecessary...
> ...but it is 3x to 10x slower and nobody dared generalizing its usage.
>
> {0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
> 0.1 . 237.128} collect: [:e |
>        [String streamContents: [:s | e absPrintExactlyOn: s base: 10]] bench
>        ->[String streamContents: [:s | e printOn: s base: 10]] bench]
>
> {'12131.77364527095 per second.'->'63358.65653738505 per second.'.
> '1535.292941411718 per second.'->'6756.64867026595 per second.'.
> '653.669266146771 per second.'->'6667.066586682664 per second.'.
> '1004.199160167966 per second.'->'5857.82843431314 per second.'.
> '8732.85342931414 per second.'->'26025.3949210158 per second.'.
> '8635.87282543491 per second.'->'19715.45690861827 per second.'.
> '2666.26674665067 per second.'->'13040.99180163967 per second.'}
>
> Nicolas
>

Reply | Threaded
Open this post in threaded view
|

Re: printing literals exactly (was isSelfEvaluating)

Nicolas Cellier
Done, that was simple.

But now we need using a Parser able to parse a decimal representation
of a Float without accumulating rounding errors.
That is SqNumberParser.

Untill then, we won't interpret correctly the decompiled code we
printed correctly...

Nicolas

2009/10/31 Nicolas Cellier <[hidden email]>:

> Hehe, I've got a plan.
>
> Use storeOn: rather than printOn: to produce the decompileString.
> It will be the same for all literals, but Float in which I will
> override storeOn:
>
> My plan is to print exactly if isFinite, or invoke a message pattern
> otherwise (Float nan, Float infinity, Float infinity negated).
> Note that these exceptional values are not literals (I already fixed that).
>
> Nicolas
>
> 2009/10/31 Nicolas Cellier <[hidden email]>:
>> 2009/10/31 Nicolas Cellier <[hidden email]>:
>>> 2009/10/31 Stéphane Rollandin <[hidden email]>:
>>>>>> If the meaning of #isLiteral is to indicate that what is printed can be
>>>>>> read back (i.e. will be correctly parsed) then I think it is a very useful
>>>>>> message that we should keep.
>>>>>
>>>>> #isLiteral mainly indicates which objects can be created at compile time.
>>>>> They are literally inserted in the compiled method. This must match the
>>>>> syntax definition of Squeak. There is no question about not keeping it.
>>>>
>>>> now I'm confused. are all objects anwering true to #isLiteral also have a
>>>> printed form that can be read back ? should they ?
>>>>
>>>> Stef
>>>>
>>>
>>> I think this is used as a feature at least in Decompiler.
>>>
>>> But can they all be read back ?
>>> Float can't always with the current implementation (they don't print exactly).
>>>
>>> (Compiler evaluate: Float halfPi printString) = Float halfPi
>>>
>>> Nicolas
>>>
>>
>> By the way, there is a workaround in CompiledMethod>>#=
>>
>> self isFloat ifTrue: [...]
>>
>> The #halt: in there sounds like calling for a better fix.
>> For example, the workaround does not work with a literal Array of Float...
>>
>> Nor does it deal with infinity:
>> (Float class compile: (Float class >> #initialize) decompileString
>>                classified: nil
>>                notifying: requestor
>>                trailer: Float class defaultMethodTrailer
>>                ifFail: [^nil]) method = (Float class >> #initialize)
>>
>> We have an excellent absPrintExactlyOn:base: that avoids extra digits
>> when unnecessary...
>> ...but it is 3x to 10x slower and nobody dared generalizing its usage.
>>
>> {0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
>> 0.1 . 237.128} collect: [:e |
>>        [String streamContents: [:s | e absPrintExactlyOn: s base: 10]] bench
>>        ->[String streamContents: [:s | e printOn: s base: 10]] bench]
>>
>> {'12131.77364527095 per second.'->'63358.65653738505 per second.'.
>> '1535.292941411718 per second.'->'6756.64867026595 per second.'.
>> '653.669266146771 per second.'->'6667.066586682664 per second.'.
>> '1004.199160167966 per second.'->'5857.82843431314 per second.'.
>> '8732.85342931414 per second.'->'26025.3949210158 per second.'.
>> '8635.87282543491 per second.'->'19715.45690861827 per second.'.
>> '2666.26674665067 per second.'->'13040.99180163967 per second.'}
>>
>> Nicolas
>>
>

Reply | Threaded
Open this post in threaded view
|

Re: printing literals exactly (was isSelfEvaluating)

Eliot Miranda-2
In reply to this post by Nicolas Cellier


On Sat, Oct 31, 2009 at 8:55 AM, Nicolas Cellier <[hidden email]> wrote:
2009/10/31 Nicolas Cellier <[hidden email]>:
> 2009/10/31 Stéphane Rollandin <[hidden email]>:
>>>> If the meaning of #isLiteral is to indicate that what is printed can be
>>>> read back (i.e. will be correctly parsed) then I think it is a very useful
>>>> message that we should keep.
>>>
>>> #isLiteral mainly indicates which objects can be created at compile time.
>>> They are literally inserted in the compiled method. This must match the
>>> syntax definition of Squeak. There is no question about not keeping it.
>>
>> now I'm confused. are all objects anwering true to #isLiteral also have a
>> printed form that can be read back ? should they ?
>>
>> Stef
>>
>
> I think this is used as a feature at least in Decompiler.
>
> But can they all be read back ?
> Float can't always with the current implementation (they don't print exactly).
>
> (Compiler evaluate: Float halfPi printString) = Float halfPi
>
> Nicolas
>

By the way, there is a workaround in CompiledMethod>>#=

self isFloat ifTrue: [...]

The #halt: in there sounds like calling for a better fix.
For example, the workaround does not work with a literal Array of Float...

Right.  It doesn't deal with NaNs either.  But it was good enough for my needs (checking that modifications to the compiler did or did not produce different compiled methods).  I could live with the false positive of Float class>>initialize.  One thing that could work here is to extend analogousCodeTo: to literals and then use it.  For Float it could compare the bit patterns except for NaN, and arrange that NaNs compare as equal, or it could compare the bit patterns so that different NaNs compare differently.  I suspect that comparing NaNs as equal is the right thing to do.  As far as execution goes one NaN should be as good as another right?


Nor does it deal with infinity:
(Float class compile: (Float class >> #initialize) decompileString
               classified: nil
               notifying: requestor
               trailer: Float class defaultMethodTrailer
               ifFail: [^nil]) method = (Float class >> #initialize)

We have an excellent absPrintExactlyOn:base: that avoids extra digits
when unnecessary...
...but it is 3x to 10x slower and nobody dared generalizing its usage.

{0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
0.1 . 237.128} collect: [:e |
       [String streamContents: [:s | e absPrintExactlyOn: s base: 10]] bench
       ->[String streamContents: [:s | e printOn: s base: 10]] bench]

{'12131.77364527095 per second.'->'63358.65653738505 per second.'.
'1535.292941411718 per second.'->'6756.64867026595 per second.'.
'653.669266146771 per second.'->'6667.066586682664 per second.'.
'1004.199160167966 per second.'->'5857.82843431314 per second.'.
'8732.85342931414 per second.'->'26025.3949210158 per second.'.
'8635.87282543491 per second.'->'19715.45690861827 per second.'.
'2666.26674665067 per second.'->'13040.99180163967 per second.'}

Nicolas




Reply | Threaded
Open this post in threaded view
|

Re: printing literals exactly (was isSelfEvaluating)

Nicolas Cellier
2009/10/31 Eliot Miranda <[hidden email]>:

>
>
> On Sat, Oct 31, 2009 at 8:55 AM, Nicolas Cellier
> <[hidden email]> wrote:
>>
>> 2009/10/31 Nicolas Cellier <[hidden email]>:
>> > 2009/10/31 Stéphane Rollandin <[hidden email]>:
>> >>>> If the meaning of #isLiteral is to indicate that what is printed can
>> >>>> be
>> >>>> read back (i.e. will be correctly parsed) then I think it is a very
>> >>>> useful
>> >>>> message that we should keep.
>> >>>
>> >>> #isLiteral mainly indicates which objects can be created at compile
>> >>> time.
>> >>> They are literally inserted in the compiled method. This must match
>> >>> the
>> >>> syntax definition of Squeak. There is no question about not keeping
>> >>> it.
>> >>
>> >> now I'm confused. are all objects anwering true to #isLiteral also have
>> >> a
>> >> printed form that can be read back ? should they ?
>> >>
>> >> Stef
>> >>
>> >
>> > I think this is used as a feature at least in Decompiler.
>> >
>> > But can they all be read back ?
>> > Float can't always with the current implementation (they don't print
>> > exactly).
>> >
>> > (Compiler evaluate: Float halfPi printString) = Float halfPi
>> >
>> > Nicolas
>> >
>>
>> By the way, there is a workaround in CompiledMethod>>#=
>>
>> self isFloat ifTrue: [...]
>>
>> The #halt: in there sounds like calling for a better fix.
>> For example, the workaround does not work with a literal Array of Float...
>
> Right.  It doesn't deal with NaNs either.  But it was good enough for my
> needs (checking that modifications to the compiler did or did not produce
> different compiled methods).  I could live with the false positive of Float
> class>>initialize.  One thing that could work here is to extend
> analogousCodeTo: to literals and then use it.  For Float it could compare
> the bit patterns except for NaN, and arrange that NaNs compare as equal, or
> it could compare the bit patterns so that different NaNs compare
> differently.  I suspect that comparing NaNs as equal is the right thing to
> do.  As far as execution goes one NaN should be as good as another right?

Hi Eliot,

NaNs are not valid literals anyway, so we should not bother too much.
Since http://bugs.squeak.org/view.php?id=6983 Float nan isLiteral -> false.

Well, there is a way to produce a NaN literal, but that is a bug!
See http://bugs.squeak.org/view.php?id=6982
It will go away when using SqNumberParser.

Nicolas


>>
>> Nor does it deal with infinity:
>> (Float class compile: (Float class >> #initialize) decompileString
>>                classified: nil
>>                notifying: requestor
>>                trailer: Float class defaultMethodTrailer
>>                ifFail: [^nil]) method = (Float class >> #initialize)
>>
>> We have an excellent absPrintExactlyOn:base: that avoids extra digits
>> when unnecessary...
>> ...but it is 3x to 10x slower and nobody dared generalizing its usage.
>>
>> {0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
>> 0.1 . 237.128} collect: [:e |
>>        [String streamContents: [:s | e absPrintExactlyOn: s base: 10]]
>> bench
>>        ->[String streamContents: [:s | e printOn: s base: 10]] bench]
>>
>> {'12131.77364527095 per second.'->'63358.65653738505 per second.'.
>> '1535.292941411718 per second.'->'6756.64867026595 per second.'.
>> '653.669266146771 per second.'->'6667.066586682664 per second.'.
>> '1004.199160167966 per second.'->'5857.82843431314 per second.'.
>> '8732.85342931414 per second.'->'26025.3949210158 per second.'.
>> '8635.87282543491 per second.'->'19715.45690861827 per second.'.
>> '2666.26674665067 per second.'->'13040.99180163967 per second.'}
>>
>> Nicolas
>>
>
>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Re: printing literals exactly (was isSelfEvaluating)

Colin Putney
In reply to this post by Nicolas Cellier

On 31-Oct-09, at 9:05 AM, Nicolas Cellier wrote:

> Hehe, I've got a plan.
>
> Use storeOn: rather than printOn: to produce the decompileString.
> It will be the same for all literals, but Float in which I will
> override storeOn:
>
> My plan is to print exactly if isFinite, or invoke a message pattern
> otherwise (Float nan, Float infinity, Float infinity negated).
> Note that these exceptional values are not literals (I already fixed  
> that).

And to generalize a bit more, the classes that were implementing  
#isSelfEvaluating could instead override #storeOn: to send #printOn:,  
and get a "prettier" result than the #storeOn: implemented in Object.

Colin

Reply | Threaded
Open this post in threaded view
|

Re: printing literals exactly (was isSelfEvaluating)

Andreas.Raab
In reply to this post by Nicolas Cellier
On a related issue, I notice that (for example):

        WeakArray with: 1 with: 2.

still prints as #(1 2) - shouldn't Array>>isLiteral have a guard saying
"self class == Array ifFalse[^false]"?

Cheers,
   - Andres

Nicolas Cellier wrote:

> Hehe, I've got a plan.
>
> Use storeOn: rather than printOn: to produce the decompileString.
> It will be the same for all literals, but Float in which I will
> override storeOn:
>
> My plan is to print exactly if isFinite, or invoke a message pattern
> otherwise (Float nan, Float infinity, Float infinity negated).
> Note that these exceptional values are not literals (I already fixed that).
>
> Nicolas
>
> 2009/10/31 Nicolas Cellier <[hidden email]>:
>> 2009/10/31 Nicolas Cellier <[hidden email]>:
>>> 2009/10/31 Stéphane Rollandin <[hidden email]>:
>>>>>> If the meaning of #isLiteral is to indicate that what is printed can be
>>>>>> read back (i.e. will be correctly parsed) then I think it is a very useful
>>>>>> message that we should keep.
>>>>> #isLiteral mainly indicates which objects can be created at compile time.
>>>>> They are literally inserted in the compiled method. This must match the
>>>>> syntax definition of Squeak. There is no question about not keeping it.
>>>> now I'm confused. are all objects anwering true to #isLiteral also have a
>>>> printed form that can be read back ? should they ?
>>>>
>>>> Stef
>>>>
>>> I think this is used as a feature at least in Decompiler.
>>>
>>> But can they all be read back ?
>>> Float can't always with the current implementation (they don't print exactly).
>>>
>>> (Compiler evaluate: Float halfPi printString) = Float halfPi
>>>
>>> Nicolas
>>>
>> By the way, there is a workaround in CompiledMethod>>#=
>>
>> self isFloat ifTrue: [...]
>>
>> The #halt: in there sounds like calling for a better fix.
>> For example, the workaround does not work with a literal Array of Float...
>>
>> Nor does it deal with infinity:
>> (Float class compile: (Float class >> #initialize) decompileString
>>                classified: nil
>>                notifying: requestor
>>                trailer: Float class defaultMethodTrailer
>>                ifFail: [^nil]) method = (Float class >> #initialize)
>>
>> We have an excellent absPrintExactlyOn:base: that avoids extra digits
>> when unnecessary...
>> ...but it is 3x to 10x slower and nobody dared generalizing its usage.
>>
>> {0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
>> 0.1 . 237.128} collect: [:e |
>>        [String streamContents: [:s | e absPrintExactlyOn: s base: 10]] bench
>>        ->[String streamContents: [:s | e printOn: s base: 10]] bench]
>>
>> {'12131.77364527095 per second.'->'63358.65653738505 per second.'.
>> '1535.292941411718 per second.'->'6756.64867026595 per second.'.
>> '653.669266146771 per second.'->'6667.066586682664 per second.'.
>> '1004.199160167966 per second.'->'5857.82843431314 per second.'.
>> '8732.85342931414 per second.'->'26025.3949210158 per second.'.
>> '8635.87282543491 per second.'->'19715.45690861827 per second.'.
>> '2666.26674665067 per second.'->'13040.99180163967 per second.'}
>>
>> Nicolas
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Re: printing literals exactly (was isSelfEvaluating)

Nicolas Cellier
2009/10/31 Andreas Raab <[hidden email]>:

> On a related issue, I notice that (for example):
>
>        WeakArray with: 1 with: 2.
>
> still prints as #(1 2) - shouldn't Array>>isLiteral have a guard saying
> "self class == Array ifFalse[^false]"?
>
> Cheers,
>  - Andres
>

Yes probably.
Array did not have any subclass in st-80, so that did not matter at that time.

Nicolas

> Nicolas Cellier wrote:
>>
>> Hehe, I've got a plan.
>>
>> Use storeOn: rather than printOn: to produce the decompileString.
>> It will be the same for all literals, but Float in which I will
>> override storeOn:
>>
>> My plan is to print exactly if isFinite, or invoke a message pattern
>> otherwise (Float nan, Float infinity, Float infinity negated).
>> Note that these exceptional values are not literals (I already fixed
>> that).
>>
>> Nicolas
>>
>> 2009/10/31 Nicolas Cellier <[hidden email]>:
>>>
>>> 2009/10/31 Nicolas Cellier <[hidden email]>:
>>>>
>>>> 2009/10/31 Stéphane Rollandin <[hidden email]>:
>>>>>>>
>>>>>>> If the meaning of #isLiteral is to indicate that what is printed can
>>>>>>> be
>>>>>>> read back (i.e. will be correctly parsed) then I think it is a very
>>>>>>> useful
>>>>>>> message that we should keep.
>>>>>>
>>>>>> #isLiteral mainly indicates which objects can be created at compile
>>>>>> time.
>>>>>> They are literally inserted in the compiled method. This must match
>>>>>> the
>>>>>> syntax definition of Squeak. There is no question about not keeping
>>>>>> it.
>>>>>
>>>>> now I'm confused. are all objects anwering true to #isLiteral also have
>>>>> a
>>>>> printed form that can be read back ? should they ?
>>>>>
>>>>> Stef
>>>>>
>>>> I think this is used as a feature at least in Decompiler.
>>>>
>>>> But can they all be read back ?
>>>> Float can't always with the current implementation (they don't print
>>>> exactly).
>>>>
>>>> (Compiler evaluate: Float halfPi printString) = Float halfPi
>>>>
>>>> Nicolas
>>>>
>>> By the way, there is a workaround in CompiledMethod>>#=
>>>
>>> self isFloat ifTrue: [...]
>>>
>>> The #halt: in there sounds like calling for a better fix.
>>> For example, the workaround does not work with a literal Array of
>>> Float...
>>>
>>> Nor does it deal with infinity:
>>> (Float class compile: (Float class >> #initialize) decompileString
>>>               classified: nil
>>>               notifying: requestor
>>>               trailer: Float class defaultMethodTrailer
>>>               ifFail: [^nil]) method = (Float class >> #initialize)
>>>
>>> We have an excellent absPrintExactlyOn:base: that avoids extra digits
>>> when unnecessary...
>>> ...but it is 3x to 10x slower and nobody dared generalizing its usage.
>>>
>>> {0.0. Float pi. Float pi   * 1.0e200. Float pi   * 1.0e-200 . 10.0 .
>>> 0.1 . 237.128} collect: [:e |
>>>       [String streamContents: [:s | e absPrintExactlyOn: s base: 10]]
>>> bench
>>>       ->[String streamContents: [:s | e printOn: s base: 10]] bench]
>>>
>>> {'12131.77364527095 per second.'->'63358.65653738505 per second.'.
>>> '1535.292941411718 per second.'->'6756.64867026595 per second.'.
>>> '653.669266146771 per second.'->'6667.066586682664 per second.'.
>>> '1004.199160167966 per second.'->'5857.82843431314 per second.'.
>>> '8732.85342931414 per second.'->'26025.3949210158 per second.'.
>>> '8635.87282543491 per second.'->'19715.45690861827 per second.'.
>>> '2666.26674665067 per second.'->'13040.99180163967 per second.'}
>>>
>>> Nicolas
>>>
>>
>>
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Re: printing literals exactly (was isSelfEvaluating)

Nicolas Cellier
In reply to this post by Colin Putney
2009/10/31 Colin Putney <[hidden email]>:

>
> On 31-Oct-09, at 9:05 AM, Nicolas Cellier wrote:
>
>> Hehe, I've got a plan.
>>
>> Use storeOn: rather than printOn: to produce the decompileString.
>> It will be the same for all literals, but Float in which I will
>> override storeOn:
>>
>> My plan is to print exactly if isFinite, or invoke a message pattern
>> otherwise (Float nan, Float infinity, Float infinity negated).
>> Note that these exceptional values are not literals (I already fixed
>> that).
>
> And to generalize a bit more, the classes that were implementing
> #isSelfEvaluating could instead override #storeOn: to send #printOn:, and
> get a "prettier" result than the #storeOn: implemented in Object.
>
> Colin
>
>

I think most already do storeOn: pretty well.

{1@2. 1->2. 0@0 extent: 1@1. RunArray new: 5 withAll: #bold} collect:
[:e | String streamContents: [:str | e storeOn: str]].

#('(1@2)' '(1->2)' '0@0 corner: 1@1' '(RunArray runs: #(5 ) values: #(#bold ))')

#storeOn: behaves better than #printOn: w.r.t. parenthesis,
unfortunately not all and that is a bug

{(0@0 extent: 1@1) -> 0} collect: [:e | String streamContents: [:str |
e storeOn: str]].
 #('(0@0 corner: 1@1->0)')

Nicolas