[squeak-dev] I'd like to contribute to the JSON project

Levente Uzonyi leves at caesar.elte.hu
Mon Nov 23 17:08:12 UTC 2020


On Sun, 22 Nov 2020, Tobias Pape wrote:

>
>
>> On 22. Nov 2020, at 19:37, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>> 
>> Hi Tobias,
>> 
>> On Sun, 22 Nov 2020, Tobias Pape wrote:
>> 
>>> 
>>> 
>>>> On 22. Nov 2020, at 18:51, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>>>> Hi Tobias,
>>>> On Sun, 22 Nov 2020, Tobias Pape wrote:
>>>>>> On 22. Nov 2020, at 17:46, Levente Uzonyi <leves at caesar.elte.hu> wrote:
>>>>>> Hi All,
>>>>>> Since most (every?) practical use of #respondsTo: is to check whether it's safe to send the message or not, I think, contrary to what was mentioned in this thread, that #respondsTo: does not have to return true when sending the message would not result in an MNU.
>>>>>> So, I suggest adding the following implementation to expose the dynamic nature of JsonObject:
>>>>>> JsonObject >> #respondsTo: aSymbol
>>>>>>
>>>>>> 	| precedence |
>>>>>> 	(super respondsTo: aSymbol) ifTrue: [ ^true ].
>>>>>> 	(precedence := aSymbol precedence) = 1 ifTrue: [
>>>>>> 		^self includesKey: aSymbol ].
>>>>>> 	(precedence = 3 and: [ (aSymbol indexOf: $:) = aSymbol size ]) ifTrue: [
>>>>>> 		^self includesKey: aSymbol allButLast ].
>>>>>> 	^false
>>>>> That's nice! but why not make it simpler?
>>>>> JsonObject >> #respondsTo: aSymbol
>>>>>
>>>>> 	| precedence |
>>>>> 	(super respondsTo: aSymbol) ifTrue: [ ^true ].
>>>>> 	aSymbol isSimpleGetter ifTrue: [^self includesKey: aSymbol].
>>>>> 	aSymbol isSimpleSetter ifTrue: [^self includesKey: aSymbol asSimpleGetter].
>>>>> 	^false
>>>> Three reasons:
>>>> 1. performance
>>>> | j s |
>>>> Smalltalk garbageCollect.
>>>> j := JsonObject new
>>>> 	foo: 1;
>>>> 	bar: 2;
>>>> 	baz: 3;
>>>> 	yourself.
>>>> s := Symbol allSymbols.
>>>> {
>>>> 	[ s do: [ :each | ] ] bench.
>>>> 	[ s do: [ :each | j respondsTo: each ] ] bench.
>>>> 	[ s do: [ :each | j respondsTo2: each ] ] bench. "Your suggested implementation"
>>>> }
>>>> #(
>>>> 	'1,630 per second. 613 microseconds per run. 0 % GC time.'
>>>> 	'19 per second. 52.7 milliseconds per run. 0.09992 % GC time.'
>>>> 	'1.18 per second. 850 milliseconds per run. 32.81709 % GC time.'
>>>> )
>>>> Okay, that may not be too a realistic workload. The reason of the extreme
>>>> slowdown and high GC time is rapid interning and GCing of Symbols
>>>> created by #asSimpleGetter.
>>>> If you change s to a handcrafted array that avoids Symbol creation, like
>>>> s := #(yourself foo foo: bar bar: baz baz: foobar foobar: name name:)
>>>> the numbers get better but still not as good as my suggestion:
>>>> #(
>>>> 	'4,970,000 per second. 201 nanoseconds per run. 38.02 % GC time.'
>>>> 	'147,000 per second. 6.82 microseconds per run. 1.74 % GC time.'
>>>> 	'92,300 per second. 10.8 microseconds per run. 1.09978 % GC time.')
>>> 
>>> I thought you'd say that.
>>> But "precedence" is one of the most obscure things around that part in the image.
>>> 
>>> 
>>>> 2. backwards compatibility
>>>> #isSimpleSetter and #isSimpleGetter are available since Squeak 5.3. I use this code in 5.1 and 5.2 images as well.
>>> 
>>> Yea, Pre 5.3 I'd have said #asMutator.
>>> 
>>>> 3. to use the same mechanism as #doesNotUnderstand:
>>>> Have a look at that method.
>>> 
>>> 
>>> Then I'd rather say change DNU too.
>>> If you're down that hole (dnu/respondsTo) anyways, I don't buy the performance argument anymore.
>>> 
>>> Not everything has to be as fast as possible.
>> 
>> You seem to ignore that #doesNotUnderstand: is the most often used method of JsonObject.
>> I assume you don't use the JSON package in production images, hence you don't care about performance.
>
> I do.
> It never has been the bottleneck.
>
>> I do, so I'm not willing to change the implementation of #doesNotUnderstand: in my fork of the JSON package unless performance is at least as good as it is now.
>
> I just want the image to remain tractable.

Does having a method or two implemented in an external package affect 
that? Also, have you ever had a look at how other stuff is implemented in 
that package?

> Performance is nice. But if you rely on performance with the JSOn stuff,
> subclass the JsonObject and implement your keys as messages? That ought to be the fastest way, no?

It depends on how your JsonObjects are created.  If you parse a json from 
an external source, you can't do that unless you hardcode the structure of 
the json into your application.

> I though it was meant to be that way.
>
> That said, I rarely remain in the JSON space for longer than necessary; I'd rather have proper objects and only convert on "the edges"

See above.


Levente

>
> I'm not against fast things.
> I'm merely a bit startled by fast things that are harder to understand than necessary…
>
> Best regards
> 	-Tobias
>
> PS: Levente, your code is almost always the fastest variant of anything we discuss on here. That's amazing in itself. Don't get the impression I'm not amazed by that ;)
>
>> 
>> 
>> Levente
>> 
>>> 
>>> Best regards
>>> 	-Tobias
>>> 
>>>> Levente
>>>>> -Tobias
>>>>>> Levente
>>>>>> On Sun, 22 Nov 2020, Thiede, Christoph wrote:


More information about the Squeak-dev mailing list