The fact that there is more than you want is precisely why you want to make
classes for the
data you *do* want.

I do have kit for streaming JSON out directly without creating JSON data
internally,
but I'm still trying to find a good way to stream JSON in creating wanted
objects
on-the-fly so that the unwanted data are never stored.  I think it can be
done from
the same schema language that I use to generate classes.

On Mon, 28 Feb 2022 at 20:09, Kasper Osterbye <kasper.oster...@gmail.com>
wrote:

> Thanks Richard,
>
> I tend to agree with your design experience. As it happens, in my concrete
> code I get JSON back from a github api which serves me more than I want. I
> am therefore not interested in making classes for those aspects of the data
> I throw out.
>
> The way I handle this in practice myself is to introduce a local variable
> for each level. Makes it easier to debug too.
>
> Best,
>
> Kasper
>
> On 27 Feb 2022, at 00.42, Richard O'Keefe <rao...@gmail.com> wrote:
>
> I was bemused to realise that I've actually been programming
> for literally 50 years. It finally seeped through my thick
> skull I make enough mistakes that if it's hard to read, I
> probably got it wrong.  And THIS code fragment is hard to
> read.  I don't care if you use parentheses or pipes, it's
> hard to read either way.  Oh, the pipes make the structure
> easier to see, true.  But I am still left guessing what it
> is FOR.  What's it SUPPOSED to mean?  And the problem is that
> there are some abstractions missing.  Of course this is JSON's
> fault.
>
> This is the first code smell, and in my experience it is
> almost ALWAYS a code smell:  you are using JSON as a
> "processing" data structure instead of as a "communication"
> syntax.  Using JSON inside your program, instead of at the
> edges, means that the semantics gets scattered all over the
> code, which leads to complexity and inconsistency.
>
> The convention I follow is that data structure more complicated
> than a string or an array of numbers has a Smalltalk class
> Whatsit>>asJson converts an instance to a JSON value
> Whatsit class>>fromJson: converts a JSON value to an instance.
> I'll start with
>    topLevel := TopLevelWhatsit fromJson: someStream nextJson.
> and from then on I'm working with pure Smalltalk.
>
> This has the extra benefit of validating the input right away.
> I don't want my program running for several hours and then
> running into trouble because some component of the JSON value
> is missing or ill-formed.
>
> In practice, the time cost of converting JSON to (application-
> specific) Smalltalk is quite small compared with the cost of
> reading the JSON in the first place, and there can be seriously
> worthwhile savings in memory.
>
> For this example, we'd be looking at
>    topLevel tree blobs
>       collect: [:each | each path]
>       thenSelect: [:path | path hasAnyExtension: #('md' 'mic')]
>
> My Filename class has methods
>   has[Any]Extension:[ignoringCase:]
> which I have shamelessly exploited here.  I like the
> way that they hide the structure of a Filename.
>
> The portmanteau methods
> Collection>>collect:thenSelect:
> Collection>>select:thenCollect:
> have existed in Pharo as long as Pharo has existed.
> They have two rationales:
> (a) improve readability
> (b) permit optimisation by eliminating an intermediate collection.
> Sequences exploit (b). Sets could too but happen not to.
>
> THEREFORE, here are free implementations of
> Set>>collect:thenSelect: and Set>>select:thenCollect:
> consistent with Pharo's Set>>collect:
>
> collect: collectBlock thenSelect: selectBlock
>   "Override Collection>>collect:thenSelect: like OrderedCollection.
>     Beware: 'self species' is often inappropriate, as in #collect:."
>   |newSet|
>   newSet := self species new: self size.
>   self do: [:each |
>     |item|
>     item := collectBlock value: each.
>       (selectBlock value: each) ifTrue: [newSet add: item]].
>   ^newSet
>
> select: selectBlock thenCollect: collectBlock
>   "Override Collection>>select:thenCollect: like OrderedCollection.
>     Beware: 'self species' is often inappropriate, as in #collect:."
>    |newSet|
>    newSet := self species new: self size.
>    self do: [:each |
>      (selectBlock value: each) ifTrue: [
>        newSet add: (collectBlock value: each)]].
>    ^newSet
>
>
>
> On Wed, 26 Jan 2022 at 22:19, Kasper Osterbye <kasper.oster...@gmail.com>
> wrote:
>
>> Cheers all
>>
>> I have noticed that I often ends up with quite a number of nested
>> expressions, for example:
>>
>> (((json at: 'tree')
>>         select: [ :e | (e at: 'type') = ‘blob' ])
>>                 collect: [:e | Path from: (e at: 'path')])
>>                         select: [ :p | p segments last
>>                                 in: [ :name | (name endsWith: '.md') |
>> (name endsWith: '.mic') ] ]
>>
>> What kind of proposals (if any) have been for a different syntax which
>> could give a more streamlined syntax?
>>
>> My own thinking has been around an alternative to the cascade semicolon.
>> What symbol to use does not matter for me, but something like
>> json at: ‘tree' º
>>         select: [ :e | ((e at: 'type') = 'blob’)]º
>>         collect: [:e | Path from: (e at: 'path’)]º
>>         select: [ :p | p segments last
>>                 in: [ :name | (name endsWith: '.md') | (name endsWith:
>> '.mic') ] ]
>>
>> Basically, a send the right hand expression to the result of the left
>> hand expression.
>>
>> Has anyone ever tried this, or is it just one of the many small
>> annoyances best left alone?
>>
>> Best,
>>
>> Kasper
>
>
>

Reply via email to