Literals

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

Literals

Debiller 777
You know, literals are quite useful in case when you want to shorten some object initialization. For example #() and {} for arrays and $[]for byte arrays. However, if there is a way to add custom literals, for example for sets (something like #{} I guess)? how to do it? and can some special kind of objects for creating literals easily be added to Pharo? 
Reply | Threaded
Open this post in threaded view
|

Re: Literals

Clément Béra
Not really.

You can use ClassVariables though. Here's an example for Sets:

Object subclass: #MyClass
instanceVariableNames: ''
classVariableNames: 'MyClassVar'
package: 'MyPackage'

MyClass class>>initialize
    super initialize.
    MyClassVar := Set new.

MyClass>>foo
    self bar: MyClassVar

Obviously sets are not as easy to deal with. You cannot mutate empty arrays/bytearrays, if you concatenate something it creates a new object. You can add things in sets. So you need to be careful... You can make the object read-only to avoid issues (MyClassVar beReadOnlyObject).



On Fri, Apr 27, 2018 at 3:19 PM, Debiller 777 <[hidden email]> wrote:
You know, literals are quite useful in case when you want to shorten some object initialization. For example #() and {} for arrays and $[]for byte arrays. However, if there is a way to add custom literals, for example for sets (something like #{} I guess)? how to do it? and can some special kind of objects for creating literals easily be added to Pharo? 



--
Reply | Threaded
Open this post in threaded view
|

Re: Literals

Esteban A. Maringolo
Hi Clément,

On 27/04/2018 10:32, Clément Bera wrote:
> Obviously sets are not as easy to deal with. You cannot mutate empty
> arrays/bytearrays, if you concatenate something it creates a new object.
> You can add things in sets. So you need to be careful... You can make
> the object read-only to avoid issues (MyClassVar beReadOnlyObject).

Sorry, but I can't understand how a class variable could allow you to
use a new literal.

As far as I knew the only way to have new literals was to modify the
compiler.

So if you want #{} to create a new empty set, or #{1 1 2} to create a
Set with 1 and 2 as elements, there is no way to do it.

Or this %{$a -> 1. 'foo' -> false. 'baz' -> #{1 1 2}} to create a
dictionary with such set as literal. :)

Regards,

--
Esteban A. Maringolo

Reply | Threaded
Open this post in threaded view
|

Re: Literals

Richard Sargent
Administrator
On Fri, Apr 27, 2018 at 2:08 PM, Esteban A. Maringolo <[hidden email]> wrote:
Hi Clément,

On 27/04/2018 10:32, Clément Bera wrote:
> Obviously sets are not as easy to deal with. You cannot mutate empty
> arrays/bytearrays, if you concatenate something it creates a new object.
> You can add things in sets. So you need to be careful... You can make
> the object read-only to avoid issues (MyClassVar beReadOnlyObject).

Sorry, but I can't understand how a class variable could allow you to
use a new literal.

As far as I knew the only way to have new literals was to modify the
compiler.

Yes.

VA Smalltalk has an interesting syntax extension which allows an arbitrary expression to be a compile-time literal.
Going by memory, something like ##(Dictionary new at: #a put: self something; at: #b put: self somethingElse; yourself).

Of course, the problem with that is it will not change if the implementations of the messages it sends entail some changes over time. 


So if you want #{} to create a new empty set, or #{1 1 2} to create a
Set with 1 and 2 as elements, there is no way to do it.

Or this %{$a -> 1. 'foo' -> false. 'baz' -> #{1 1 2}} to create a
dictionary with such set as literal. :)

Regards,

--
Esteban A. Maringolo


Reply | Threaded
Open this post in threaded view
|

Re: Literals

Esteban A. Maringolo
On 27/04/2018 15:35, Richard Sargent wrote:
> On Fri, Apr 27, 2018 at 2:08 PM, Esteban A. Maringolo
> <[hidden email] <mailto:[hidden email]>> wrote:

>     As far as I knew the only way to have new literals was to modify the
>     compiler.
>
>
> Yes.
>
> VA Smalltalk has an interesting syntax extension which allows an
> arbitrary expression to be a compile-time literal.
> Going by memory, something like ##(Dictionary new at: #a put: self
> something; at: #b put: self somethingElse; yourself).

Dolphin Smalltalk provides that ##() literal as well since a decade at
least, so you have the full expression that gave origin to that literal,
but you don't need to compute it every time it is accessed.

Although I don't remember seeing it with Dictionaries, but more with
string concatenations or "magic numbers" like seconds in a day stored as
##(24 * 60 * 60).

Regards,


--
Esteban A. Maringolo

Reply | Threaded
Open this post in threaded view
|

Re: Literals

Clément Béra
The guy who asked the question said: "...when you want to shorten some object initialization"

Using ClassVariable is an alternative way to shorten object initialization, reading a ClassVariable is almost the same performance as reading a literal, so that looked like a good alternative to me. Both the ClassVariable and the literal have the same issues (same object so if you mutate it you have to deal with it).

But yes, it's not a new literal.

For new literals, you can extend the compiler or hard patch thing:

MyClass>>foo
^ #bar

(MyClass>>#foo) literalAt: ((MyClass>>#foo) literals indexOf: #bar) put: Set new.

MyClass new foo 

>>> a Set ()

Obviously it depends what you mean by literal, the latter code uses the literal bytecode instruction, which does not make the pushed object a literal object...

On Fri, Apr 27, 2018 at 8:59 PM, Esteban A. Maringolo <[hidden email]> wrote:
On 27/04/2018 15:35, Richard Sargent wrote:
> On Fri, Apr 27, 2018 at 2:08 PM, Esteban A. Maringolo
> <[hidden email] <mailto:[hidden email]>> wrote:

>     As far as I knew the only way to have new literals was to modify the
>     compiler.
>
>
> Yes.
>
> VA Smalltalk has an interesting syntax extension which allows an
> arbitrary expression to be a compile-time literal.
> Going by memory, something like ##(Dictionary new at: #a put: self
> something; at: #b put: self somethingElse; yourself).

Dolphin Smalltalk provides that ##() literal as well since a decade at
least, so you have the full expression that gave origin to that literal,
but you don't need to compute it every time it is accessed.

Although I don't remember seeing it with Dictionaries, but more with
string concatenations or "magic numbers" like seconds in a day stored as
##(24 * 60 * 60).

Regards,


--
Esteban A. Maringolo




--
Reply | Threaded
Open this post in threaded view
|

Re: Literals

Esteban A. Maringolo
oh, you were talking about how te VM views the object,
I was thinking in terms of how the compiler sees the text.

So I'm talking about literals "syntax".

Thanks anyway for the "trick" :)

On 27/04/2018 16:34, Clément Bera wrote:

> The guy who asked the question said: "...when you want to shorten some
> object initialization"
>
> Using ClassVariable is an alternative way to shorten object
> initialization, reading a ClassVariable is almost the same performance
> as reading a literal, so that looked like a good alternative to me. Both
> the ClassVariable and the literal have the same issues (same object so
> if you mutate it you have to deal with it).
>
> But yes, it's not a new literal.
>
> For new literals, you can extend the compiler or hard patch thing:
>
> MyClass>>foo
> ^ #bar
>
> (MyClass>>#foo) literalAt: ((MyClass>>#foo) literals indexOf: #bar) put:
> Set new.
>
> MyClass new foo 
>
>>>> a Set ()
>
> Obviously it depends what you mean by literal, the latter code uses the
> literal bytecode instruction, which does not make the pushed object a
> literal object...


--
Esteban A. Maringolo

Reply | Threaded
Open this post in threaded view
|

Re: Literals

Richard Sargent
Administrator
On Fri, Apr 27, 2018 at 3:58 PM, Esteban A. Maringolo <[hidden email]> wrote:
oh, you were talking about how te VM views the object,
I was thinking in terms of how the compiler sees the text.

So I'm talking about literals "syntax".

Thanks anyway for the "trick" :)

Another common technique is a "once block". Teach Block how to evaluate itself once and to use its cached result the next time.

It's not as fast as a literal, but it is a pretty effective way to have a clean implementation with as complex code as one could wish.
Clear the cache when saving the image or at image start up or ... whenever seems good (such as when you change the implementation of what was cached.

e.g.
[Dictionary new
at: #a put: self something;
at: #b put: self somethingElse;
yourself]
once

 

On 27/04/2018 16:34, Clément Bera wrote:
> The guy who asked the question said: "...when you want to shorten some
> object initialization"
>
> Using ClassVariable is an alternative way to shorten object
> initialization, reading a ClassVariable is almost the same performance
> as reading a literal, so that looked like a good alternative to me. Both
> the ClassVariable and the literal have the same issues (same object so
> if you mutate it you have to deal with it).
>
> But yes, it's not a new literal.
>
> For new literals, you can extend the compiler or hard patch thing:
>
> MyClass>>foo
> ^ #bar
>
> (MyClass>>#foo) literalAt: ((MyClass>>#foo) literals indexOf: #bar) put:
> Set new.
>
> MyClass new foo 
>
>>>> a Set ()
>
> Obviously it depends what you mean by literal, the latter code uses the
> literal bytecode instruction, which does not make the pushed object a
> literal object...


--
Esteban A. Maringolo


Reply | Threaded
Open this post in threaded view
|

Re: Literals

Ben Coman
In reply to this post by Clément Béra


On 28 April 2018 at 03:34, Clément Bera <[hidden email]> wrote:
The guy who asked the question said: "...when you want to shorten some object initialization"

Using ClassVariable is an alternative way to shorten object initialization, reading a ClassVariable is almost the same performance as reading a literal, so that looked like a good alternative to me. Both the ClassVariable and the literal have the same issues (same object so if you mutate it you have to deal with it).

But yes, it's not a new literal.

For new literals, you can extend the compiler or hard patch thing:

MyClass>>foo
^ #bar

(MyClass>>#foo) literalAt: ((MyClass>>#foo) literals indexOf: #bar) put: Set new.

MyClass new foo 

>>> a Set ()

Obviously it depends what you mean by literal, the latter code uses the literal bytecode instruction, which does not make the pushed object a literal object...

Maybe pool dictionaries provide a half-way house...

cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Literals

Bing Liang
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Literals

Richard O'Keefe
The ## syntax that some Smalltalks have (Smalltalk/X, for
example, which calls it a Dolphin extension) is related
to Common Lisp's
   #.e      the result of evaluating e at *read* time,
            taken as a literal
   #,e      the result of evaluating e at *load* time,
            taken as a literal.
This reminds us there are several times that a ## form
could be evaluated:
 - in the parser, when a method is parsed (before code
   generation)
 - when code is generated
 - when code is generated AND whenever the image is
   restored
 - when the value is first needed (I'd prefer this)
 - when the value is first needed in a thread (that
   is, each thread that encounters it will evaluate
   it just once, so each thread may see a different
   value).

One continuing annoyance in Smalltalk is that I cannot
put a Fraction, a Date, a Time, or a DateAndTime in a
literal.  It would be nice to have #1969-07-20 or #1/2
or #16:40:32 as literals and they contain no expressions
that could result in any confusion about when they are
evaluated and cannot be changed any more than a character
literal can.

Curly brace syntax {e1. ... en} is an expression form,
not a literal form.  Similar forms for sets of several
kinds and dictionaries of several kinds are supported
in my Smalltalk, and they are indeed useful, but they
are especially useful because they are *not* literals
but create new values every time.


On 28 April 2018 at 16:13, lb <[hidden email]> wrote:
Hi,
I think the question is 
How automaticly create literal's objects , not initialize.
e.g
'aString'
#aSymbol
{ anArray}
#[]
............

Cheers  Liang


Reply | Threaded
Open this post in threaded view
|

Re: Literals

Peter Uhnak
What would entail actually extending the syntax and adding the set literal?

From my brief observations (when I was discussing this with OP on discord):

* adding a new AST node
* extend RBParser
* extend IRMethod/IRTranslator... maybe generating bytecode for `{ ... } asSet` instead would be enough? (not sure how debugger would react to this)

anything else? Would VM changes be required?

Peter

On Sat, Apr 28, 2018 at 8:33 AM, Richard O'Keefe <[hidden email]> wrote:
The ## syntax that some Smalltalks have (Smalltalk/X, for
example, which calls it a Dolphin extension) is related
to Common Lisp's
   #.e      the result of evaluating e at *read* time,
            taken as a literal
   #,e      the result of evaluating e at *load* time,
            taken as a literal.
This reminds us there are several times that a ## form
could be evaluated:
 - in the parser, when a method is parsed (before code
   generation)
 - when code is generated
 - when code is generated AND whenever the image is
   restored
 - when the value is first needed (I'd prefer this)
 - when the value is first needed in a thread (that
   is, each thread that encounters it will evaluate
   it just once, so each thread may see a different
   value).

One continuing annoyance in Smalltalk is that I cannot
put a Fraction, a Date, a Time, or a DateAndTime in a
literal.  It would be nice to have #1969-07-20 or #1/2
or #16:40:32 as literals and they contain no expressions
that could result in any confusion about when they are
evaluated and cannot be changed any more than a character
literal can.

Curly brace syntax {e1. ... en} is an expression form,
not a literal form.  Similar forms for sets of several
kinds and dictionaries of several kinds are supported
in my Smalltalk, and they are indeed useful, but they
are especially useful because they are *not* literals
but create new values every time.


On 28 April 2018 at 16:13, lb <[hidden email]> wrote:
Hi,
I think the question is 
How automaticly create literal's objects , not initialize.
e.g
'aString'
#aSymbol
{ anArray}
#[]
............

Cheers  Liang



Reply | Threaded
Open this post in threaded view
|

Re: Literals

Richard O'Keefe
A

On 28 April 2018 at 20:21, Peter Uhnák <[hidden email]> wrote:
What would entail actually extending the syntax and adding the set literal?

From my brief observations (when I was discussing this with OP on discord):

* adding a new AST node
* extend RBParser
* extend IRMethod/IRTranslator... maybe generating bytecode for `{ ... } asSet` instead would be enough? (not sure how debugger would react to this)

anything else? Would VM changes be required?

 I added
​    '{' binarySelector expr '.' ... '.' expr ['.'] '}'
to my ​compiler because I was sick of other people being
able to write stuff more elegantly in Python than I could
in Smalltalk.  Here the binarySelector controls what kind
of set:
 =    Set
 ==   IdentitySet
 ?=   CaseInsensitiveSet
 <    SortedSet (splay trees)
 >    SortedSet (with comparison reversed)
 <>   TernarySet (ternary search string for strings).
I'm not happy with the syntax, but it's the least ugly I've
been able to find.  Having syntax only for Set would be so
limiting there'd be no real point.

So.  No change to the scanner.
No change to the abstract syntax trees.
{== x. y}
generates the same syntax tree that
((IdentitySet new: 2) add: x; add: y; yourself)
would have done.
And therefore no change to the back end code
generator.
The *only* change was the parsing routine that
responds to '{'.

The fundamental issue is WHY you want an extension
to the syntax.  In my case, the {binarySelector exprs}
syntax for sets and corresponding #{binarySelector maplets}
syntax for dictionaries were to let me approximate the
brevity of Python and Javascript.  I didn't need new
*semantics*.

In contrast, the ##(expr) syntax in Dolphin, Smalltalk/X,
and whatever others does NOT offer brevity at all but
DOES offer new semantics.  To the limited, not to say
derisory, extent to which I understand the Dolphin compiler,
it does have a special StOptimizedNode type of AST node
for ##(...) forms.  I don't *think* any VM changes are
needed, unless of course you want to be able to decompile
the byte-code and recover the ##(expr) source.  I don't
have a Windows box any more, so I can't run Dolphin,
sorry, just admire it.  I can say that it takes care not
to put literals inside a ##(expr) form in the literal
table.

Reply | Threaded
Open this post in threaded view
|

Re: Literals

Denis Kudriashov
In reply to this post by Richard Sargent
Hi.
сб, 28 апр. 2018 г., 1:26 Richard Sargent <[hidden email]>:
On Fri, Apr 27, 2018 at 3:58 PM, Esteban A. Maringolo <[hidden email]> wrote:
oh, you were talking about how te VM views the object,
I was thinking in terms of how the compiler sees the text.

So I'm talking about literals "syntax".

Thanks anyway for the "trick" :)

Another common technique is a "once block". Teach Block how to evaluate itself once and to use its cached result the next time.



It's not as fast as a literal, but it is a pretty effective way to have a clean implementation with as complex code as one could wish.
Clear the cache when saving the image or at image start up or ... whenever seems good (such as when you change the implementation of what was cached.

e.g.
[Dictionary new
at: #a put: self something;
at: #b put: self somethingElse;
yourself]
once

 

On 27/04/2018 16:34, Clément Bera wrote:
> The guy who asked the question said: "...when you want to shorten some
> object initialization"
>
> Using ClassVariable is an alternative way to shorten object
> initialization, reading a ClassVariable is almost the same performance
> as reading a literal, so that looked like a good alternative to me. Both
> the ClassVariable and the literal have the same issues (same object so
> if you mutate it you have to deal with it).
>
> But yes, it's not a new literal.
>
> For new literals, you can extend the compiler or hard patch thing:
>
> MyClass>>foo
> ^ #bar
>
> (MyClass>>#foo) literalAt: ((MyClass>>#foo) literals indexOf: #bar) put:
> Set new.
>
> MyClass new foo 
>
>>>> a Set ()
>
> Obviously it depends what you mean by literal, the latter code uses the
> literal bytecode instruction, which does not make the pushed object a
> literal object...


--
Esteban A. Maringolo


Reply | Threaded
Open this post in threaded view
|

Re: Literals

Richard Sargent
Administrator
In reply to this post by Debiller 777
Debiller 777 wrote
> You know, literals are quite useful in case when you want to shorten some
> object initialization. For example #() and {} for arrays and $[]for byte
> arrays. However, if there is a way to add custom literals, for example for
> sets (something like #{} I guess)? how to do it? and can some special kind
> of objects for creating literals easily be added to Pharo?

The discussion on this topic has been quite interesting. However, I want to
circle back to this original question; I think we've wandered from it in
some respects.

The original motivation was "when you want to shorten some object
initialization". Typically, this kind of driver is a performance issue. As
in, "I want to be able to initialize my instances with minimal overhead" so
that e.g. the cost of creating instances is minimized and I can create and
discard instances easily and frequently.

I'm not saying that is the only motivation, but it is largely what I will
address here.

A number of messages discussed somewhat more elaborate syntax for literals,
such as the example for a date #{'2018-05-01') or something close to that.
And someone else will surely want #{'14:30'} for much the same
justification. And yet others will want something else altogether. My of my
all-time favourite design rules was something I read in 1989, loosely called
the 0, 1, infinity rule. As soon as we go beyond one of something, there are
an arbitrary number of possibilities we must deal with. That's not a burden
we want to put on the compiler (or more likely on the parser).

We could imagine that the syntax is a little more elaborate, such as #{Date
'2018-05-01'} in which case the parser could automatically send the
#fromString: message to the receiver Date using the argument of the string.
Such an approach would give a general solution to a simple subset of the
possible initializers one might encounter.

However, it wouldn't handle other kinds of initialization, such as the
Dictionary example I mentioned in my earlier response. It also wouldn't
handle the issue of the implementation of #fromString: being changed and
failing to recompile the literal that was generated independently of it. For
the sake of argument, I think we can reasonably assert that #fromString:
would be assumed to be correct and any changes in its implementation would
not impact the literal that was previously and correctly created from that
literal string.


So, we have a proposal that with a small increase in the syntactic burden of
the language does address a reasonable subset of the originally stated
problem. But, it doesn't solve the general problem. For that reason alone, I
don't agree with increasing the syntax of the language for it.


Another respondent mentioned pool variables. These have the benefit that the
name can be entirely informative and their values can be recomputed any time
one wishes. In fact, they may already be the correct and complete answer.
They aren't without their own costs, of course. Obviously, they must be
defined before they can be referenced in the code that uses them. This
pretty much requires a multiple package approach, requiring one package to
define the pool variables (perhaps with only a place-holder value) and
another package with the code that needs them.

(VA Smalltalk has a technique that allows them to be defined in the same
package, but at a terrible price: their definitions are opaque to the
standard Smalltalk tools. We can discuss this on a separate thread if anyone
wants to know more about that.)


There is also the "once" block that I mentioned elsewhere. It typically uses
a dictionary to cache the result of the first evaluation and then provide
the look up on subsequent evaluations. One could also add a cached result
instance variable to Block and avoid such a look up. It's still not as fast
as a pool variable, of course.


As a side note, I would like to remind everyone about Kent Beck's comments
on literals. I'm paraphrasing him, but essentially there are only a very few
literals which should be allowed to run around naked. The may be 0, 1, '',
and possibly -1. Certainly every other literal should be encapsulated in an
intention revealing name. Does May 1st mean something? If one is going to
use it as I did in the examples above, it had better be given a name that
everyone will be able to understand. For example, any reader would
understand Float pi and the distinction between it and Double pi. A string
of random digits takes considerably more parsing on the part of the reader
to understand its intent.


Lastly, I would encourage the original poster to elaborate on what problem
or problems he is really trying to solve. (Over the years, I ave encountered
many users who request a feature to solve a problem that isn't the real
problem they need to solve. Programmers, too, make the same mistake.)



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: Literals

Sean P. DeNigris
Administrator
In reply to this post by Denis Kudriashov
Denis Kudriashov wrote
> We have similar mechanizm in Pharo. Look at
> http://dionisiydk.blogspot.fr/2016/07/magic-with-pharo-reflectivity.html

Wow! That's really cool. I like that we can do it without adding *any*
syntax. Tiny syntax is one of the more special things about the Smalltalk
language.



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Cheers,
Sean