[Pharo-users] Re: Too many parenthesis - a matter of syntax

2022-02-26 Thread Richard O'Keefe
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 
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


[Pharo-users] Re: Too many parenthesis - a matter of syntax

2022-02-26 Thread Kasper Osterbye
All the answers have been good. I am somewhat provoked (in the good sense of 
forcing me to think) by Siemen who sort of think of it as a code-smell.

Best,

Kasper

> On 26 Feb 2022, at 17.14, Siemen Baader  wrote:
> 
> Hi Kasper,
> 
> perhaps not what you are asking, but I find that this kind of nesting happens 
> to me when parsing serialized data (web page sources or JSON as in your 
> example). For me, the root cause of the problem is that these data structures 
> are not represented by real classes in my code. I often start with what you 
> are showing in a Playground, but then refactor it into specific parsers for 
> the web sites I am scraping. The parsing selectors go into classes that 
> mirror the parts of the data I am interested in. I find this to be more 
> declarative and maintainable, and more natural in the Pharo environment with 
> its browsers and code extractors. 
> 
> I hope this is of any use :)


[Pharo-users] Re: Too many parenthesis - a matter of syntax

2022-02-26 Thread Siemen Baader
Hi Kasper,

perhaps not what you are asking, but I find that this kind of nesting
happens to me when parsing serialized data (web page sources or JSON as in
your example). For me, the root cause of the problem is that these data
structures are not represented by real classes in my code. I often start
with what you are showing in a Playground, but then refactor it into
specific parsers for the web sites I am scraping. The parsing selectors go
into classes that mirror the parts of the data I am interested in. I find
this to be more declarative and maintainable, and more natural in the Pharo
environment with its browsers and code extractors.

I hope this is of any use :)

cheers
Siemen

On Fri, Jan 28, 2022 at 11:55 PM Vitor Medina Cruz 
wrote:

> I think that's OK when you can choose when to use parentheses. If you
> think it would improve readability it is ok to use it, the problem is to be
> forced to use it even when you think it decreases readability, what I
> believe to be the case in discussion.
>
> On Thu, Jan 27, 2022 at 3:24 PM Russ Whaley  wrote:
>
>> What I like about parentheses (and I hate parentheses) is that it allows
>> me to view/describe the intent of the code. When parens are not used, it is
>> up to me (perhaps years later) to determine whether the original developer
>> (sometimes me) understood (or not) the actual 'order of processing'.
>> Parens - or another vehicle - should help me understand the intent (as
>> would detailed comments) - so I can devise tests (oh yeah, are those
>> available, too?) for the intent - even if it is just me in the debugger.
>>
>> So, I'm for whatever helps me understand the intent of the code - even if
>> there is some slick way to nest everything. I generally prefer breaking
>> nested processes down into multiple steps. Benchmarking rarely shows
>> significant performance differences, for me.
>>
>> (and I've used parentheses 7 times in this one email!)  :-)
>>
>> Russ
>>
>> On Wed, Jan 26, 2022 at 4:20 AM 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
>>
>>
>>
>> --
>> Russ Whaley
>> whaley.r...@gmail.com
>>
>