why is concat of Symbols a string?

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

why is concat of Symbols a string?

Peter Uhnak
Hi,

why is the concatenation of symbols a string?

e.g. #desc, #Name -> 'descName'

this means that I have to always wrap in parentheses and recast, or stream it, e.g.

(#desc, #Name) asSymbol -> #descName
Symbol streamContents: [ :s | s << #desc; << #Name ] -> #descName

both of which introduce extraneous syntactical clutter.
The technical reason seems to be ByteSymbol>>#species returning ByteString, but I have no idea why it has to be this complicated.

Thanks,
Peter

Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Clément Béra
Hi,

All symbols are interned in the Symbol table. If one does (#foo , #bar , #baz) and each returned value would be a symbol, then both #foobar and #foobarbaz would be registered in the symbol table.

I would guess that's why the concatenated value is a string and not a symbol, to avoid registering many unused symbols. But maybe I am wrong.

If for your use case you need to concatenate symbols and get a symbol out of it, you can define a new method in Symbol to do what you want.

For example:

Symbol >> ,, arg
^ (self , arg) asSymbol

Then

#foo ,, #bar 

Answers directly the symbol #foobar.

Best,




On Sat, Mar 4, 2017 at 11:36 AM, Peter Uhnak <[hidden email]> wrote:
Hi,

why is the concatenation of symbols a string?

e.g. #desc, #Name -> 'descName'

this means that I have to always wrap in parentheses and recast, or stream it, e.g.

(#desc, #Name) asSymbol -> #descName
Symbol streamContents: [ :s | s << #desc; << #Name ] -> #descName

both of which introduce extraneous syntactical clutter.
The technical reason seems to be ByteSymbol>>#species returning ByteString, but I have no idea why it has to be this complicated.

Thanks,
Peter


Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Igor Stasenko
Hmm.. symbols is usually treated like immutable object(s) in system. They tend to stay while rest of data changes.. This could explain why authors of this method
purposedly picked to use ByteString for its species to discourage using symbols for collection manipulation(s)..
Else, if you would need to change this method as well:

at: anInteger put: anObject 
"You cannot modify the receiver."

self errorNoModification

because base class #, implementation is going to use at:put: during concatenation.



On 4 March 2017 at 13:40, Clément Bera <[hidden email]> wrote:
Hi,

All symbols are interned in the Symbol table. If one does (#foo , #bar , #baz) and each returned value would be a symbol, then both #foobar and #foobarbaz would be registered in the symbol table.

I would guess that's why the concatenated value is a string and not a symbol, to avoid registering many unused symbols. But maybe I am wrong.

If for your use case you need to concatenate symbols and get a symbol out of it, you can define a new method in Symbol to do what you want.

For example:

Symbol >> ,, arg
^ (self , arg) asSymbol

Then

#foo ,, #bar 

Answers directly the symbol #foobar.

Best,




On Sat, Mar 4, 2017 at 11:36 AM, Peter Uhnak <[hidden email]> wrote:
Hi,

why is the concatenation of symbols a string?

e.g. #desc, #Name -> 'descName'

this means that I have to always wrap in parentheses and recast, or stream it, e.g.

(#desc, #Name) asSymbol -> #descName
Symbol streamContents: [ :s | s << #desc; << #Name ] -> #descName

both of which introduce extraneous syntactical clutter.
The technical reason seems to be ByteSymbol>>#species returning ByteString, but I have no idea why it has to be this complicated.

Thanks,
Peter





--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Peter Uhnak
I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
$, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...

Peter


On Sun, Mar 05, 2017 at 04:29:39AM +0200, Igor Stasenko wrote:

> Hmm.. symbols is usually treated like immutable object(s) in system. They
> tend to stay while rest of data changes.. This could explain why authors of
> this method
> purposedly picked to use ByteString for its species to discourage using
> symbols for collection manipulation(s)..
> Else, if you would need to change this method as well:
>
> at: anInteger put: anObject
> "You cannot modify the receiver."
>
> self errorNoModification
>
> because base class #, implementation is going to use at:put: during
> concatenation.
>
>
>
> On 4 March 2017 at 13:40, Clément Bera <[hidden email]> wrote:
>
> > Hi,
> >
> > All symbols are interned in the Symbol table. If one does (#foo , #bar ,
> > #baz) and each returned value would be a symbol, then both #foobar and
> > #foobarbaz would be registered in the symbol table.
> >
> > I would guess that's why the concatenated value is a string and not a
> > symbol, to avoid registering many unused symbols. But maybe I am wrong.
> >
> > If for your use case you need to concatenate symbols and get a symbol out
> > of it, you can define a new method in Symbol to do what you want.
> >
> > For example:
> >
> > Symbol >> ,, arg
> > ^ (self , arg) asSymbol
> >
> > Then
> >
> > #foo ,, #bar
> >
> > Answers directly the symbol #foobar.
> >
> > Best,
> >
> >
> >
> >
> > On Sat, Mar 4, 2017 at 11:36 AM, Peter Uhnak <[hidden email]> wrote:
> >
> >> Hi,
> >>
> >> why is the concatenation of symbols a string?
> >>
> >> e.g. #desc, #Name -> 'descName'
> >>
> >> this means that I have to always wrap in parentheses and recast, or
> >> stream it, e.g.
> >>
> >> (#desc, #Name) asSymbol -> #descName
> >> Symbol streamContents: [ :s | s << #desc; << #Name ] -> #descName
> >>
> >> both of which introduce extraneous syntactical clutter.
> >> The technical reason seems to be ByteSymbol>>#species returning
> >> ByteString, but I have no idea why it has to be this complicated.
> >>
> >> Thanks,
> >> Peter
> >>
> >>
> >
>
>
> --
> Best regards,
> Igor Stasenko.

Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Sven Van Caekenberghe-2
I also think that allowing concatenation on Symbols does not violate their immutability contract.

As a thought experiment, what could be the problem with adding

Symbol >> , arg
        ^ (self , arg) asSymbol

?

(I have found the original issue raised annoying as well)

> On 5 Mar 2017, at 11:35, Peter Uhnak <[hidden email]> wrote:
>
> I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
> $, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...
>
> Peter
>
>
> On Sun, Mar 05, 2017 at 04:29:39AM +0200, Igor Stasenko wrote:
>> Hmm.. symbols is usually treated like immutable object(s) in system. They
>> tend to stay while rest of data changes.. This could explain why authors of
>> this method
>> purposedly picked to use ByteString for its species to discourage using
>> symbols for collection manipulation(s)..
>> Else, if you would need to change this method as well:
>>
>> at: anInteger put: anObject
>> "You cannot modify the receiver."
>>
>> self errorNoModification
>>
>> because base class #, implementation is going to use at:put: during
>> concatenation.
>>
>>
>>
>> On 4 March 2017 at 13:40, Clément Bera <[hidden email]> wrote:
>>
>>> Hi,
>>>
>>> All symbols are interned in the Symbol table. If one does (#foo , #bar ,
>>> #baz) and each returned value would be a symbol, then both #foobar and
>>> #foobarbaz would be registered in the symbol table.
>>>
>>> I would guess that's why the concatenated value is a string and not a
>>> symbol, to avoid registering many unused symbols. But maybe I am wrong.
>>>
>>> If for your use case you need to concatenate symbols and get a symbol out
>>> of it, you can define a new method in Symbol to do what you want.
>>>
>>> For example:
>>>
>>> Symbol >> ,, arg
>>> ^ (self , arg) asSymbol
>>>
>>> Then
>>>
>>> #foo ,, #bar
>>>
>>> Answers directly the symbol #foobar.
>>>
>>> Best,
>>>
>>>
>>>
>>>
>>> On Sat, Mar 4, 2017 at 11:36 AM, Peter Uhnak <[hidden email]> wrote:
>>>
>>>> Hi,
>>>>
>>>> why is the concatenation of symbols a string?
>>>>
>>>> e.g. #desc, #Name -> 'descName'
>>>>
>>>> this means that I have to always wrap in parentheses and recast, or
>>>> stream it, e.g.
>>>>
>>>> (#desc, #Name) asSymbol -> #descName
>>>> Symbol streamContents: [ :s | s << #desc; << #Name ] -> #descName
>>>>
>>>> both of which introduce extraneous syntactical clutter.
>>>> The technical reason seems to be ByteSymbol>>#species returning
>>>> ByteString, but I have no idea why it has to be this complicated.
>>>>
>>>> Thanks,
>>>> Peter
>>>>
>>>>
>>>
>>
>>
>> --
>> Best regards,
>> Igor Stasenko.
>


Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Martin McClure-2
On 03/05/2017 03:01 AM, Sven Van Caekenberghe wrote:
I also think that allowing concatenation on Symbols does not violate their immutability contract.

As a thought experiment, what could be the problem with adding

Symbol >> , arg
	^ (self , arg) asSymbol

?

Aside from the infinite recursion (I suspect you meant super rather than self) :-) , I wouldn't have any problem with that.


(I have found the original issue raised annoying as well)

On 5 Mar 2017, at 11:35, Peter Uhnak [hidden email] wrote:

I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
$, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...

Somewhat unfortunately, imho, Smalltalk Strings are mutable. I've not seen this feature used often, except by internal operations that could just as well be using a CharacterBuffer or whatever would replace String as the mutable thing if you made String immutable.

Regards,

-Martin

Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Sven Van Caekenberghe-2

> On 5 Mar 2017, at 19:53, Martin McClure <[hidden email]> wrote:
>
> On 03/05/2017 03:01 AM, Sven Van Caekenberghe wrote:
>> I also think that allowing concatenation on Symbols does not violate their immutability contract.
>>
>> As a thought experiment, what could be the problem with adding
>>
>> Symbol >> , arg
>> ^ (self , arg) asSymbol
>>
>> ?
>>
>
> Aside from the infinite recursion (I suspect you meant super rather than self) :-) , I wouldn't have any problem with that.

Haha, I copied it from lower in the thread, but shame on me that I didn't see that right away !

>> (I have found the original issue raised annoying as well)
>>
>>
>>> On 5 Mar 2017, at 11:35, Peter Uhnak <[hidden email]>
>>>  wrote:
>>>
>>> I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
>>> $, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...
>>>
> Somewhat unfortunately, imho, Smalltalk Strings are mutable. I've not seen this feature used often, except by internal operations that could just as well be using a CharacterBuffer or whatever would replace String as the mutable thing if you made String immutable.

Yes, this distinction, with a default for immutable ones, would be good. We got #beReadOnlyObject in Pharo, so I guess we can start experimenting. Especially literal strings should be read only.

> Regards,
>
> -Martin


Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Sven Van Caekenberghe-2
In reply to this post by Martin McClure-2
Here is a concrete proposal:

https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String

This gives the following assertions:

        "Concatenating 2 symbols results in abother symbol"
        self assert: (#foo , #bar) == #foobar.
       
        "Concatenating the empty symbol does not change a symbol"
        self assert: (#foo, emptySymbol) == #foo.
        self assert: (emptySymbol, #foo) == #foo.
       
        "Strings and symbols can still be mixed, the receiver determines the result type"
        "Symbol receiver gives symbol result"
        self assert: (#foo , 'bar') == #foobar.
        "String receiver gives string result"
        self deny: ('foo' , #bar) == #foobar.
        self assert: ('foo' , #bar) equals: #foobar.
        self assert: ('foo' , #bar) equals: 'foobar'.

> On 5 Mar 2017, at 19:53, Martin McClure <[hidden email]> wrote:
>
> On 03/05/2017 03:01 AM, Sven Van Caekenberghe wrote:
>> I also think that allowing concatenation on Symbols does not violate their immutability contract.
>>
>> As a thought experiment, what could be the problem with adding
>>
>> Symbol >> , arg
>> ^ (self , arg) asSymbol
>>
>> ?
>>
>
> Aside from the infinite recursion (I suspect you meant super rather than self) :-) , I wouldn't have any problem with that.
>
>>
>> (I have found the original issue raised annoying as well)
>>
>>
>>> On 5 Mar 2017, at 11:35, Peter Uhnak <[hidden email]>
>>>  wrote:
>>>
>>> I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
>>> $, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...
>>>
> Somewhat unfortunately, imho, Smalltalk Strings are mutable. I've not seen this feature used often, except by internal operations that could just as well be using a CharacterBuffer or whatever would replace String as the mutable thing if you made String immutable.
>
> Regards,
>
> -Martin


Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Peter Uhnak
Thanks Sven!

this looks good, and now also behaves same way as concating other collections (that is, the result type is the receivers' type).  

Peter


On Mon, Mar 06, 2017 at 10:54:32AM +0100, Sven Van Caekenberghe wrote:

> Here is a concrete proposal:
>
> https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String
>
> This gives the following assertions:
>
> "Concatenating 2 symbols results in abother symbol"
> self assert: (#foo , #bar) == #foobar.
>
> "Concatenating the empty symbol does not change a symbol"
> self assert: (#foo, emptySymbol) == #foo.
> self assert: (emptySymbol, #foo) == #foo.
>
> "Strings and symbols can still be mixed, the receiver determines the result type"
> "Symbol receiver gives symbol result"
> self assert: (#foo , 'bar') == #foobar.
> "String receiver gives string result"
> self deny: ('foo' , #bar) == #foobar.
> self assert: ('foo' , #bar) equals: #foobar.
> self assert: ('foo' , #bar) equals: 'foobar'.
>
> > On 5 Mar 2017, at 19:53, Martin McClure <[hidden email]> wrote:
> >
> > On 03/05/2017 03:01 AM, Sven Van Caekenberghe wrote:
> >> I also think that allowing concatenation on Symbols does not violate their immutability contract.
> >>
> >> As a thought experiment, what could be the problem with adding
> >>
> >> Symbol >> , arg
> >> ^ (self , arg) asSymbol
> >>
> >> ?
> >>
> >
> > Aside from the infinite recursion (I suspect you meant super rather than self) :-) , I wouldn't have any problem with that.
> >
> >>
> >> (I have found the original issue raised annoying as well)
> >>
> >>
> >>> On 5 Mar 2017, at 11:35, Peter Uhnak <[hidden email]>
> >>>  wrote:
> >>>
> >>> I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
> >>> $, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...
> >>>
> > Somewhat unfortunately, imho, Smalltalk Strings are mutable. I've not seen this feature used often, except by internal operations that could just as well be using a CharacterBuffer or whatever would replace String as the mutable thing if you made String immutable.
> >
> > Regards,
> >
> > -Martin
>
>

Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Ben Coman
In reply to this post by Sven Van Caekenberghe-2


On Mon, Mar 6, 2017 at 5:54 PM, Sven Van Caekenberghe <[hidden email]> wrote:
Here is a concrete proposal:

https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String

This gives the following assertions:

        "Concatenating 2 symbols results in abother symbol"
        self assert: (#foo , #bar) == #foobar.

        "Concatenating the empty symbol does not change a symbol"
        self assert: (#foo, emptySymbol) == #foo.
        self assert: (emptySymbol, #foo) == #foo.

        "Strings and symbols can still be mixed, the receiver determines the result type"
        "Symbol receiver gives symbol result"
        self assert: (#foo , 'bar') == #foobar.
        "String receiver gives string result"
        self deny: ('foo' , #bar) == #foobar.
        self assert: ('foo' , #bar) equals: #foobar.
        self assert: ('foo' , #bar) equals: 'foobar'.


Those last two seem contradictory.  
cheers -ben
 

> On 5 Mar 2017, at 19:53, Martin McClure <[hidden email]> wrote:
>
> On 03/05/2017 03:01 AM, Sven Van Caekenberghe wrote:
>> I also think that allowing concatenation on Symbols does not violate their immutability contract.
>>
>> As a thought experiment, what could be the problem with adding
>>
>> Symbol >> , arg
>>      ^ (self , arg) asSymbol
>>
>> ?
>>
>
> Aside from the infinite recursion (I suspect you meant super rather than self) :-) , I wouldn't have any problem with that.
>
>>
>> (I have found the original issue raised annoying as well)
>>
>>
>>> On 5 Mar 2017, at 11:35, Peter Uhnak <[hidden email]>
>>>  wrote:
>>>
>>> I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
>>> $, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...
>>>
> Somewhat unfortunately, imho, Smalltalk Strings are mutable. I've not seen this feature used often, except by internal operations that could just as well be using a CharacterBuffer or whatever would replace String as the mutable thing if you made String immutable.
>
> Regards,
>
> -Martin



Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Sven Van Caekenberghe-2

> On 6 Mar 2017, at 14:12, Ben Coman <[hidden email]> wrote:
>
>
>
> On Mon, Mar 6, 2017 at 5:54 PM, Sven Van Caekenberghe <[hidden email]> wrote:
> Here is a concrete proposal:
>
> https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String
>
> This gives the following assertions:
>
>         "Concatenating 2 symbols results in abother symbol"
>         self assert: (#foo , #bar) == #foobar.
>
>         "Concatenating the empty symbol does not change a symbol"
>         self assert: (#foo, emptySymbol) == #foo.
>         self assert: (emptySymbol, #foo) == #foo.
>
>         "Strings and symbols can still be mixed, the receiver determines the result type"
>         "Symbol receiver gives symbol result"
>         self assert: (#foo , 'bar') == #foobar.
>         "String receiver gives string result"
>         self deny: ('foo' , #bar) == #foobar.
>         self assert: ('foo' , #bar) equals: #foobar.
>         self assert: ('foo' , #bar) equals: 'foobar'.
>
>
> Those last two seem contradictory.

No, Symbols and String can be used interchangeably in Pharo in lots of contexts. Particularly when comparing them, it makes no difference, all the following are/have always been true, independent of this change:

 #foo = 'foo'
 'foo' = #foo
 #foo = #foo
 'foo' = 'foo'

But maybe it is a bit confusing with an extra comment.

> cheers -ben
>  
>
> > On 5 Mar 2017, at 19:53, Martin McClure <[hidden email]> wrote:
> >
> > On 03/05/2017 03:01 AM, Sven Van Caekenberghe wrote:
> >> I also think that allowing concatenation on Symbols does not violate their immutability contract.
> >>
> >> As a thought experiment, what could be the problem with adding
> >>
> >> Symbol >> , arg
> >>      ^ (self , arg) asSymbol
> >>
> >> ?
> >>
> >
> > Aside from the infinite recursion (I suspect you meant super rather than self) :-) , I wouldn't have any problem with that.
> >
> >>
> >> (I have found the original issue raised annoying as well)
> >>
> >>
> >>> On 5 Mar 2017, at 11:35, Peter Uhnak <[hidden email]>
> >>>  wrote:
> >>>
> >>> I don't need (or want) to mutate the receiver. Actually I thought that String is also immutable.
> >>> $, could just return a new symbol instance instead. Concating symbols is quite practical for metaprogramming, as most things are named with symbols and compare by identity...
> >>>
> > Somewhat unfortunately, imho, Smalltalk Strings are mutable. I've not seen this feature used often, except by internal operations that could just as well be using a CharacterBuffer or whatever would replace String as the mutable thing if you made String immutable.
> >
> > Regards,
> >
> > -Martin


Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Ben Coman
On Mon, Mar 6, 2017 at 9:21 PM, Sven Van Caekenberghe <[hidden email]> wrote:

>
>> On 6 Mar 2017, at 14:12, Ben Coman <[hidden email]> wrote:
>>
>>
>>
>> On Mon, Mar 6, 2017 at 5:54 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>> Here is a concrete proposal:
>>
>> https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String
>>
>> This gives the following assertions:
>>
>>         "Concatenating 2 symbols results in abother symbol"
>>         self assert: (#foo , #bar) == #foobar.
>>
>>         "Concatenating the empty symbol does not change a symbol"
>>         self assert: (#foo, emptySymbol) == #foo.
>>         self assert: (emptySymbol, #foo) == #foo.
>>
>>         "Strings and symbols can still be mixed, the receiver determines the result type"
>>         "Symbol receiver gives symbol result"
>>         self assert: (#foo , 'bar') == #foobar.
>>         "String receiver gives string result"
>>         self deny: ('foo' , #bar) == #foobar.
>>         self assert: ('foo' , #bar) equals: #foobar.
>>         self assert: ('foo' , #bar) equals: 'foobar'.
>>
>>
>> Those last two seem contradictory.
>
> No, Symbols and String can be used interchangeably in Pharo in lots of contexts. Particularly when comparing them, it makes no difference, all the following are/have always been true, independent of this change:
>
>  #foo = 'foo'
>  'foo' = #foo
>  #foo = #foo
>  'foo' = 'foo'

Ah-ha... gotchya.  always something more to learn.

So those last three lines a testing that it is a String?
This meaning is pretty well hidden in the implicit behaviour.
Why not just...
    self assert: (#foo , 'bar') isString
which seems to better "says what it means"

If such is poor form in general,
I'm curious to what degree such rules may be relaxed for unit tests.
Could it be considered something like premature optimisation
to make the test too generic??  If isString latter causes a problem later,
deal with it then.

====
On another slightly different point,
this might be one case where #assert:#equals is less clear than using "="

Its also easy to mis-think the following is contradictory
>>         self deny: ('foo' , #bar) == #foobar.
>>         self assert: ('foo' , #bar) equals: #foobar.

where the alternative here makes the distinction more clear...
    self deny: ('foo' , #bar) == #foobar.
    self assert: ('foo' , #bar) = #foobar.


cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Sven Van Caekenberghe-2
Ben,

I tried to avoid #isString and #isSymbol and I thought it was clear that #assert:equals: used #= but I agree that I could be more explicit. Here is the changed version of the unit test (.2 of slice):

testConcatenationIsSymbol
        "Concatenating 2 symbols results in another symbol"
        self assert: (#foo , #bar) isSymbol.
        self assert: (#foo , #bar) == #foobar.
       
        "Concatenating the empty Symbol does not change a Symbol"
        self assert: (#foo , emptySymbol) == #foo.
        self assert: (emptySymbol , #foo) == #foo.
       
        "Strings and Symbols can still be mixed, the receiver determines the result type"
        "Symbol receiver gives Symbol result"
        self assert: (#foo , 'bar') isSymbol.
        self assert: (#foo , 'bar') == #foobar.
        "String receiver gives String result"
        self assert: ('foo' , #bar) isString.
        self assert: ('foo' , #bar) = 'foobar'.
        "Strings and Symbols still compare content-wise"
        self assert: ('foo' , #bar) = #foobar.
        "But Strings and Symbols are not identical"
        self deny: ('foo' , #bar) == #foobar.


> On 6 Mar 2017, at 15:18, Ben Coman <[hidden email]> wrote:
>
> On Mon, Mar 6, 2017 at 9:21 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>>
>>> On 6 Mar 2017, at 14:12, Ben Coman <[hidden email]> wrote:
>>>
>>>
>>>
>>> On Mon, Mar 6, 2017 at 5:54 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>>> Here is a concrete proposal:
>>>
>>> https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String
>>>
>>> This gives the following assertions:
>>>
>>>        "Concatenating 2 symbols results in abother symbol"
>>>        self assert: (#foo , #bar) == #foobar.
>>>
>>>        "Concatenating the empty symbol does not change a symbol"
>>>        self assert: (#foo, emptySymbol) == #foo.
>>>        self assert: (emptySymbol, #foo) == #foo.
>>>
>>>        "Strings and symbols can still be mixed, the receiver determines the result type"
>>>        "Symbol receiver gives symbol result"
>>>        self assert: (#foo , 'bar') == #foobar.
>>>        "String receiver gives string result"
>>>        self deny: ('foo' , #bar) == #foobar.
>>>        self assert: ('foo' , #bar) equals: #foobar.
>>>        self assert: ('foo' , #bar) equals: 'foobar'.
>>>
>>>
>>> Those last two seem contradictory.
>>
>> No, Symbols and String can be used interchangeably in Pharo in lots of contexts. Particularly when comparing them, it makes no difference, all the following are/have always been true, independent of this change:
>>
>> #foo = 'foo'
>> 'foo' = #foo
>> #foo = #foo
>> 'foo' = 'foo'
>
> Ah-ha... gotchya.  always something more to learn.
>
> So those last three lines a testing that it is a String?
> This meaning is pretty well hidden in the implicit behaviour.
> Why not just...
>    self assert: (#foo , 'bar') isString
> which seems to better "says what it means"
>
> If such is poor form in general,
> I'm curious to what degree such rules may be relaxed for unit tests.
> Could it be considered something like premature optimisation
> to make the test too generic??  If isString latter causes a problem later,
> deal with it then.
>
> ====
> On another slightly different point,
> this might be one case where #assert:#equals is less clear than using "="
>
> Its also easy to mis-think the following is contradictory
>>>        self deny: ('foo' , #bar) == #foobar.
>>>        self assert: ('foo' , #bar) equals: #foobar.
>
> where the alternative here makes the distinction more clear...
>    self deny: ('foo' , #bar) == #foobar.
>    self assert: ('foo' , #bar) = #foobar.
>
>
> cheers -ben


Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Igor Stasenko
In reply to this post by Sven Van Caekenberghe-2


On 6 March 2017 at 15:21, Sven Van Caekenberghe <[hidden email]> wrote:

> On 6 Mar 2017, at 14:12, Ben Coman <[hidden email]> wrote:
>
>
>
> On Mon, Mar 6, 2017 at 5:54 PM, Sven Van Caekenberghe <[hidden email]> wrote:
> Here is a concrete proposal:
>
> https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String
>
> This gives the following assertions:
>
>         "Concatenating 2 symbols results in abother symbol"
>         self assert: (#foo , #bar) == #foobar.
>
>         "Concatenating the empty symbol does not change a symbol"
>         self assert: (#foo, emptySymbol) == #foo.
>         self assert: (emptySymbol, #foo) == #foo.
>
>         "Strings and symbols can still be mixed, the receiver determines the result type"
>         "Symbol receiver gives symbol result"
>         self assert: (#foo , 'bar') == #foobar.
>         "String receiver gives string result"
>         self deny: ('foo' , #bar) == #foobar.
>         self assert: ('foo' , #bar) equals: #foobar.
>         self assert: ('foo' , #bar) equals: 'foobar'.
>
>
> Those last two seem contradictory.

No, Symbols and String can be used interchangeably in Pharo in lots of contexts. Particularly when comparing them, it makes no difference, all the following are/have always been true, independent of this change:

 #foo = 'foo'
 'foo' = #foo
 #foo = #foo
 'foo' = 'foo'

But maybe it is a bit confusing with an extra comment.

You got me with this...
Hey, stop confusing people, put #== everywhere! :) 

But if seriously, #assert:equals: hides this detail from us, that's why it looks confusing..
IMO, for given case it would be better to use just straight #assert:, with explicit expression that using #= for comparands.

--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Martin McClure-2
On 03/06/2017 11:17 AM, Igor Stasenko wrote:
> You got me with this...
> Hey, stop confusing people, put #== everywhere! :)
>
> But if seriously, #assert:equals: hides this detail from us, that's why
> it looks confusing..
> IMO, for given case it would be better to use just straight #assert:,
> with explicit expression that using #= for comparands.

assert: (anExpression = someOtherExpression)

may, in some cases, be slightly more intention-revealing than

assert: anExpression equals: someOtherExpression

However, I'd like to advocate for the latter, for ease of debugging.
I've been in too many situations where a test fails an equality test,
and the failure is not easily reproducible.

In the debugger, if #assert: was used I'm left with "false" as my only
clue to what happened. OTOH, if #assert:equals: was used, I have both
the expected value and the actual value in the debugger, which is a much
better clue as to the nature of the problem.

Regards,

-Martin

Reply | Threaded
Open this post in threaded view
|

Re: why is concat of Symbols a string?

Ben Coman
In reply to this post by Sven Van Caekenberghe-2
Thanks Sven.
cheers -ben

On Tue, Mar 7, 2017 at 2:43 AM, Sven Van Caekenberghe <[hidden email]> wrote:

> Ben,
>
> I tried to avoid #isString and #isSymbol and I thought it was clear that #assert:equals: used #= but I agree that I could be more explicit. Here is the changed version of the unit test (.2 of slice):
>
> testConcatenationIsSymbol
>         "Concatenating 2 symbols results in another symbol"
>         self assert: (#foo , #bar) isSymbol.
>         self assert: (#foo , #bar) == #foobar.
>
>         "Concatenating the empty Symbol does not change a Symbol"
>         self assert: (#foo , emptySymbol) == #foo.
>         self assert: (emptySymbol , #foo) == #foo.
>
>         "Strings and Symbols can still be mixed, the receiver determines the result type"
>         "Symbol receiver gives Symbol result"
>         self assert: (#foo , 'bar') isSymbol.
>         self assert: (#foo , 'bar') == #foobar.

>         "String receiver gives String result"
>         self assert: ('foo' , #bar) isString.
>         self assert: ('foo' , #bar) = 'foobar'.
>         "Strings and Symbols still compare content-wise"
>         self assert: ('foo' , #bar) = #foobar.
>         "But Strings and Symbols are not identical"
>         self deny: ('foo' , #bar) == #foobar.
>
>
>> On 6 Mar 2017, at 15:18, Ben Coman <[hidden email]> wrote:
>>
>> On Mon, Mar 6, 2017 at 9:21 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>>>
>>>> On 6 Mar 2017, at 14:12, Ben Coman <[hidden email]> wrote:
>>>>
>>>>
>>>>
>>>> On Mon, Mar 6, 2017 at 5:54 PM, Sven Van Caekenberghe <[hidden email]> wrote:
>>>> Here is a concrete proposal:
>>>>
>>>> https://pharo.fogbugz.com/f/cases/19802/Make-sure-Symbol-concatenation-results-in-a-Symbol-not-a-String
>>>>
>>>> This gives the following assertions:
>>>>
>>>>        "Concatenating 2 symbols results in abother symbol"
>>>>        self assert: (#foo , #bar) == #foobar.
>>>>
>>>>        "Concatenating the empty symbol does not change a symbol"
>>>>        self assert: (#foo, emptySymbol) == #foo.
>>>>        self assert: (emptySymbol, #foo) == #foo.
>>>>
>>>>        "Strings and symbols can still be mixed, the receiver determines the result type"
>>>>        "Symbol receiver gives symbol result"
>>>>        self assert: (#foo , 'bar') == #foobar.
>>>>        "String receiver gives string result"
>>>>        self deny: ('foo' , #bar) == #foobar.
>>>>        self assert: ('foo' , #bar) equals: #foobar.
>>>>        self assert: ('foo' , #bar) equals: 'foobar'.
>>>>
>>>>
>>>> Those last two seem contradictory.
>>>
>>> No, Symbols and String can be used interchangeably in Pharo in lots of contexts. Particularly when comparing them, it makes no difference, all the following are/have always been true, independent of this change:
>>>
>>> #foo = 'foo'
>>> 'foo' = #foo
>>> #foo = #foo
>>> 'foo' = 'foo'
>>
>> Ah-ha... gotchya.  always something more to learn.
>>
>> So those last three lines a testing that it is a String?
>> This meaning is pretty well hidden in the implicit behaviour.
>> Why not just...
>>    self assert: (#foo , 'bar') isString
>> which seems to better "says what it means"
>>
>> If such is poor form in general,
>> I'm curious to what degree such rules may be relaxed for unit tests.
>> Could it be considered something like premature optimisation
>> to make the test too generic??  If isString latter causes a problem later,
>> deal with it then.
>>
>> ====
>> On another slightly different point,
>> this might be one case where #assert:#equals is less clear than using "="
>>
>> Its also easy to mis-think the following is contradictory
>>>>        self deny: ('foo' , #bar) == #foobar.
>>>>        self assert: ('foo' , #bar) equals: #foobar.
>>
>> where the alternative here makes the distinction more clear...
>>    self deny: ('foo' , #bar) == #foobar.
>>    self assert: ('foo' , #bar) = #foobar.
>>
>>
>> cheers -ben
>
>