[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
|