Yet Another useless Ruby 2 Idea

Yeah, I figured that out right after I had posted my message...

But still, you can see that the python syntax is quite a bit more
readable ( at least in this case ).

j.

···

On 8/4/05, David A. Black <dblack@wobblini.net> wrote:

Hi --

On Thu, 4 Aug 2005, Jeff Wood wrote:

> but beyond that, they have a cool conditional clause for the comprehensions...
>
> [ item*2 for item in items if item > 2 ]
>
> ... which lets you run a conditional filter, and then a procedure on
> the elements that passed.
>
> which would be the same as:
>
> temp = items.select { |item| item > 2 }
> temp.collect { |item| item*2 }

You don't need 'temp' there:

  items.select {|item| item > 2 }.map {|item| item * 2 }

David

--
David A. Black
dblack@wobblini.net

--
"So long, and thanks for all the fish"

Jeff Wood

Jeff Wood ha scritto:

I'm not saying there are NO features of python that are cool... I like
their list comprehensions

but, I do dislike the whitespace formatting extremely.

not that this is important, but I was'nt suggesting indentation based syntax, which I dislike for reasons (i.e. commenting may mess syntax) that do not apply to implict terminators.

Anyway, I'm not really advocating this, see the 3rd word in the subject :wink:

<snip>

[ item*2 for item in items ]

which is the same as: items.collect { |item| item*2 }

I think their version is more readable...

but beyond that, they have a cool conditional clause for the comprehensions..

[ item*2 for item in items if item > 2 ]

items.cool_method_name {|item| item*2 if item > 2}

is quite doable in ruby, just collect when yielding gives you a meaningful result, there are quite a bit of solutions.
cool_method_name is often suggested as compact_map, map_filter, select_map and others, try googling for them.

BTW, python's generator expressions are much cooler :wink:

Stephen Kellett <snail@objmedia.demon.co.uk> writes:

The number of times a visually correct Python script I've
written doesn't work because I've mixed up tabs and spaces

I cannot believe you haven't resolved this trivial problem
by simply not using tabs. Make your editor refuse to save a
buffer that contains tabs, and make it refuse to insert them.

Makefiles also mix up spaces and tabs and often fail if
you put the wrong invisible character in the wrong place.

This problem is difficult to make with a highlighting editor.

Its a nightmare. People knew that Makefile syntax was daft
before Python was born. Why anyone would want to put that
into a computer language beggars belief.

The problem with makefile syntax is its dependence on tabs;
Python fixed this. Why anyone would want to still use tabs
beggars belief.

···

--
Daniel Brockman <daniel@brockman.se>

Not to pick a fight, but that's just fine by me. Python sacrifices
nearly everything for readability. It's a language that revolves
around making code readable. If Python is occasionally more readable,
that's just fine. Ruby has a goal of being pleasant to write and work
with as well as being reasonably readable. I'd feel far more
comfortable when I work with Ruby, and it is usually quite readable. I
feel far more constrained when I write Python, but the output is
nearly always extremely readable.

The fact that Ruby can compete with Python in terms of readability is
a testament to how far it has come.

···

On 8/4/05, Jeff Wood <jeff.darklight@gmail.com> wrote:

Yeah, I figured that out right after I had posted my message...

But still, you can see that the python syntax is quite a bit more
readable ( at least in this case ).

j.

--
--
Dave Fayram (II)
dfayram@gmail.com

Hi --

Yeah, I figured that out right after I had posted my message...

But still, you can see that the python syntax is quite a bit more
readable ( at least in this case ).

I have reluctantly given up on "readable" as a useful adjective. Like
"intuitive", it's used as a term of praise but apparently (trusting
the available evidence) doesn't mean anything. (The available
evidence is people, over the years, describing some very cryptic
things as more "readable" than their, ummm, non-cryptic equivalents
:slight_smile:

In this case, I have no trouble visually parsing either. But I take
such difficulties on faith in every case.

You could also do:

   array.map {|item| item * 2 if item > 2 }.compact

though there's always the snag of cases where nil is OK as a value for
the resulting array. It's kind of hard to think how one would
implement #map_if. (Maybe something with enum_for or generator?)

David

···

On Fri, 5 Aug 2005, Jeff Wood wrote:

j.

On 8/4/05, David A. Black <dblack@wobblini.net> wrote:

Hi --

On Thu, 4 Aug 2005, Jeff Wood wrote:

but beyond that, they have a cool conditional clause for the comprehensions...

[ item*2 for item in items if item > 2 ]

... which lets you run a conditional filter, and then a procedure on
the elements that passed.

which would be the same as:

temp = items.select { |item| item > 2 }
temp.collect { |item| item*2 }

You don't need 'temp' there:

  items.select {|item| item > 2 }.map {|item| item * 2 }

David

--
David A. Black
dblack@wobblini.net

--
"So long, and thanks for all the fish"

Jeff Wood

--
David A. Black
dblack@wobblini.net

gabriele renzi wrote:

Jeff Wood ha scritto:
> I'm not saying there are NO features of python that are cool... I like
> their list comprehensions
>
> but, I do dislike the whitespace formatting extremely.

not that this is important, but I was'nt suggesting indentation based
syntax, which I dislike for reasons (i.e. commenting may mess syntax)
that do not apply to implict terminators.

Anyway, I'm not really advocating this, see the 3rd word in the subject :wink:

<snip>

> [ item*2 for item in items ]
>
> which is the same as: items.collect { |item| item*2 }
>
> I think their version is more readable...
>
> but beyond that, they have a cool conditional clause for the comprehensions..
>
> [ item*2 for item in items if item > 2 ]

items.cool_method_name {|item| item*2 if item > 2}

is quite doable in ruby, just collect when yielding gives you a
meaningful result, there are quite a bit of solutions.
cool_method_name is often suggested as compact_map, map_filter,
select_map and others, try googling for them.

BTW, python's generator expressions are much cooler :wink:

With literal lambda's and an extension to # Ruby can easily do:

  a = [1,2,3,4,5,6]

  a[ { |i| i > 2 } ] #=> [3,4,5,6]

In the new notation BTW:

  a[ -> i { i > 2 } ]

Facets already has this extension, but currently one must write:

  a[ lambda { |i| i > 2 } ]

T.

I'm a little confused then... how do you disambiguate implicit block
terminators without significant whitespace? Take for example the
following case, with no leading whitespace (to make sure it's not
significant):

  module Foo
  class Bar

That's it, just two lines, and I can define a module and a class.
Pretty nice. But what am I defining? Is the class ::Bar or Foo::Bar?
The implicit terminators could be chosen either way:

  module Foo
  end
  class Bar
  end

versus

  module Foo
    class Bar
    end
  end

Now, the syntax need not be ambiguous to the parser. Just choose a
convention. But at that point it becomes impossible to do the other
without reintroducing an explicit terminator. That would only make
things even more confusing. Some terminators explicit, others
implicit? No thank you!

In order to keep all the options currently available -- most of which
I've used personally and all of which have been used by *somebody* --
explicit terminators are necessary. The only explicit terminators I
know of are symbols (for which I think the keyword 'end' works nicely)
or a change in indentation.

Jacob Fugal

···

On 8/5/05, gabriele renzi <surrender_it@remove-yahoo.it> wrote:

not that this is important, but I was'nt suggesting indentation based
syntax, which I dislike for reasons (i.e. commenting may mess syntax)
that do not apply to implict terminators.

gabriele renzi <surrender_it@remove-yahoo.it> writes:

I was'nt suggesting indentation based syntax, which I
dislike for reasons (i.e. commenting may mess syntax) that
do not apply to implict terminators.

What do you mean, "commenting may mess syntax"?

items.cool_method_name {|item| item*2 if item > 2}

is quite doable in ruby

Except you can't collect nil values that way.

···

--
Daniel Brockman <daniel@brockman.se>

The number of times a visually correct Python script I've
written doesn't work because I've mixed up tabs and spaces

I cannot believe you haven't resolved this trivial problem
by simply not using tabs. Make your editor refuse to save a

I write lots of code in C++ and assembler, you get into a habit of using tabs to format your code. This is very hard to leave behind, you press tab without even thinking about it, its automatic. Watching most software engineers at work, I think this is pretty much the norm. Examining the source code sent to me for customer support/debugging issues leads me to the same conclusion.

The idea of pressing tab and having multiple whitespace chars inserted is horrible, it makes deleting what should be a tab a multi-delete operation. Truly dreadful.

It is very hard to change your editing/typing style from language to another when they should be the same. I want a language to be easy to use. I should not have to use a special IDE/editor to display different invisible characters - I should be concentrating on the code itself not the issues around how it is typed. Its as if driving a car I should be counting the number of kerb stones I pass rather than actually concentrating on the job at hand. Or playing one mandolin I have to count the number of frets each time a fret a note but on the other mandolin I just play the instrument. Its just nonesense. Whitespace should be that - whitespace, but Python thinks otherwise.

>The problem with makefile syntax is its dependence on tabs; Python >fixed this.

I disagree. It is another form of the same problem - mixing different forms of whitespace.

>Why anyone would want to still use tabs beggars belief.

Because it involves less typing and makes formatting a lot easier?

I think you are in a minority on this, I've yet to meet anyone that writes code that doesn't use them. In 24 years of writing software that is a reasonable sample size.

Anyway, from the replies to this thread it seems that sense prevails and Ruby users generally dislike the whitespace formatting idea.

Stephen

···

In message <87u0i4ia93.fsf@wigwam.deepwood.net>, Daniel Brockman <daniel@brockman.se> writes
--
Stephen Kellett
Object Media Limited http://www.objmedia.demon.co.uk/software.html
Computer Consultancy, Software Development
Windows C++, Java, Assembler, Performance Analysis, Troubleshooting

I completely disagree. "item for item in items if item"? How is that easy to understand?

The Ruby way may involve a few more keystrokes, but it's much more clear what's happening.

items.select {|item| item > 2 }.map {|item| item * 2 }

First you use "select", giving you an array, then you map the elements of the array to another. The temporary variables you create are obvious, unlike the Python example where you start using the variable even before you declare it, and the two tasks (selecting certain elements of the array, and manipulating those elements) are cleanly separated. To me, I can't tell if the "if item > 2" happens each time, or only once.

I think it's like lisp. Once you get used to it, you can read it an parse it efficiently, but getting there is a real pain, and until your brain is used to those constructs it isn't at all intuitive.

Ben

···

On Aug 4, 2005, at 13:20, Jeff Wood wrote:

Yeah, I figured that out right after I had posted my message...

But still, you can see that the python syntax is quite a bit more
readable ( at least in this case ).

Understood, but at the same time, it's funny that you say Python has
sacrificed nearly everything ... this from member methods that require
self as the first parameter...

Anyways, yeah, not trying to cause a fight, but I don't particularly
see that as particularly readable... a newbie looks at the code and
says, but I didn't pass 4 parameters...

I find Ruby to be quite a bit easier on my eyes that Python ... I just
really like their list syntax ...

Anyways , just putting my $0.02 in.

j.

···

On 8/4/05, Dave Fayram <dfayram@gmail.com> wrote:

On 8/4/05, Jeff Wood <jeff.darklight@gmail.com> wrote:
> Yeah, I figured that out right after I had posted my message...
>
> But still, you can see that the python syntax is quite a bit more
> readable ( at least in this case ).
>
> j.

Not to pick a fight, but that's just fine by me. Python sacrifices
nearly everything for readability. It's a language that revolves
around making code readable. If Python is occasionally more readable,
that's just fine. Ruby has a goal of being pleasant to write and work
with as well as being reasonably readable. I'd feel far more
comfortable when I work with Ruby, and it is usually quite readable. I
feel far more constrained when I write Python, but the output is
nearly always extremely readable.

The fact that Ruby can compete with Python in terms of readability is
a testament to how far it has come.

--
--
Dave Fayram (II)
dfayram@gmail.com

--
"So long, and thanks for all the fish"

Jeff Wood

Jacob Fugal ha scritto:

not that this is important, but I was'nt suggesting indentation based
syntax, which I dislike for reasons (i.e. commenting may mess syntax)
that do not apply to implict terminators.

I'm a little confused then... how do you disambiguate implicit block
terminators without significant whitespace? Take for example the
following case, with no leading whitespace (to make sure it's not
significant):

  module Foo
  class Bar

That's it, just two lines, and I can define a module and a class.
Pretty nice. But what am I defining? Is the class ::Bar or Foo::Bar?

the latter, if you wanted to write the former you should have been using the explicit form.
The rule is not hard, it's just "when there is no ambiguity, you can omit", it's just like the use of parenthesis (or is it parenses?) around arguments.
And mostly like the ";" at the end of every line that we don't ever write :wink:
But as was already pointed out this seem to be non obvious, and thus it is probably a bad idea.

Now, the syntax need not be ambiguous to the parser. Just choose a
convention. But at that point it becomes impossible to do the other
without reintroducing an explicit terminator. That would only make
things even more confusing. Some terminators explicit, others
implicit? No thank you!

just like ";", and like () around arguments to methods, afaict

···

On 8/5/05, gabriele renzi <surrender_it@remove-yahoo.it> wrote:

With that syntax, no. This would be a great place for multiple block
arguments though:

  module Enumerable
    def filter_and_map( &filter, &map )
      result =
      self.each { |el| result << map[el] if filter[el] }
      return result
    end
  end
  
  [ 1, 2, 3, 4 ].filter_and_map { |i| i % 2 == 0 } { |i| i ** 2 }
  # => [ 4, 16 ]

Currently, this would have to written (the change to the method
implementation follows easily)

  [ 1, 2, 3, 4 ].filter_and_map( lambda{ |i| ... }, lambda{ |i| ... } )

Although, once we have named parameters and have settled on a syntax
for lambdas, it wouldn't be so bad:

  [ 1, 2, 3, 4 ].filter_and_map(
    filter: { |i| ... },
    map: { |i| ... },
  )

I'm with many of the other posters in this thread, however, and find
the list comprehension syntax even better[1]. Oh, well.

Jacob Fugal

[1] I think that ary.select{ |i| ... }.map{ |i| ... } may be even more
readable than the list comprehension, but it suffers performance due
to two passes through each of the accepted elements.

···

On 8/5/05, Daniel Brockman <daniel@brockman.se> wrote:

> items.cool_method_name {|item| item*2 if item > 2}
>
> is quite doable in ruby

Except you can't collect nil values that way.

Daniel Brockman ha scritto:

gabriele renzi <surrender_it@remove-yahoo.it> writes:

I was'nt suggesting indentation based syntax, which I
dislike for reasons (i.e. commenting may mess syntax) that
do not apply to implict terminators.

What do you mean, "commenting may mess syntax"?

well, if I write

def foozer(x):
  if x >10:
   print x
  do other stuff

and I do comment out the "if" line, there is a syntax error

items.cool_method_name {|item| item*2 if item > 2}

is quite doable in ruby

Except you can't collect nil values that way.

Well, you can retain this same syntax for the common case and with various tricks (avoiding another method as argument) augment the method to handle "useful nils".
My favourite option is comparing the return value with a given parameter, defaulting to nil, so if you think you want to collect nils you can do:

items.filter_mapping(:skip) {|item| fobbar(item)? item : :skip}

Or you could throw something to skip collecting, and catch it in #cool_method. You could even write a "skip" method to throw stuff for you.

[Re: tabbing]

Stephen Kellett wrote:

[...]
The idea of pressing tab and having multiple whitespace chars inserted
is horrible, it makes deleting what should be a tab a multi-delete
operation. Truly dreadful.

Configure your editor (?)

I press <TAB> to insert 4 spaces ... <BSPC> goes back to indentation
level of line above ... if no line above, it goes to start of line.

<TAB><TAB> inserts 8 spaces, *one* <BSPC> does the same as above.
You soon get used to it when it's predictable.

If I accidentally hit 7 <TAB>s when I meant 6 - tough luck
because there's no way to go back one; so, <BSPC> and <TAB> * 6.

Pressing <RETURN> aligns with current line (that's common isn't it ?).
If you're using "hard tabs", it aligns by inserting a <TAB> character;
"soft tabs" pads with spaces.

The single advantage of "hard tabs" is to save disk space, IMO.

See if there's an editor option (or two) which mentions backspace
behaviour and give it a tweak -- then spread the word :wink:

If you don't have the options, either demand them or change your editor.

Hopefully, everyone's code can then be viewed in everyone's editor.

Stephen

daz

Ummm, maybe a closer translation would be:

  "computation for item in collection if condition"

Naming computation/item/collection/condition the same and then
declaring unreadability is a straw man.

Given the translation above, consider the following english comment of
what is actually happening:

  "do computation for each item in collection with condition"

The "do" and "each" are implicit. That's fine with me, the language
shouldn't read as full english or it will be too verbose. The only
other change is replacing "if" by "with". It be nice if the list
comprehension used "with" instead:

  manager_salaries = [e.salary for e in employees with e.manager?]
    vs.
  manager_salaries = [e.salary for e in employees if e.manager?]

Depends on who you are. Me? I like "with" better, but can live with
"if" just fine. I think the main readability argument for list
comprehensions is that the flow of the construct is similar to the
flow of the english sentence that describes it. Ok, is a
select/collect implementation less readable?

  manager_salaries = employees.
    select{ |e| e.manager? }.
    collect{ |e| e.salary }

English translation:

  "For each item in collection with condition, do computation"

NO! An argument for readability of list comprehensions is not an
argument against readability of select/each/collect etc. I love thems,
and I want to keep thems! :slight_smile: Adding list comprehensions wouldn't imply
removal of the equally readable and powerful block constructs we're
used to.

However, notice one thing about the select/collect implementation
above. We iterate through employees once and create a temporary array.
We then iterate through that temporary array again during the collect.
That seems a bit inefficient to me. The list comprehension -- with
equal readability -- removes that inefficiency.

Does Ruby need list comprehensions to solve that? Not necessarily:

  module Enumerable
    def collect_filtered(filter: filter, mapping: mapping)
      self.inject() { |c,e| filter[e] ? c << mapping[e] : c }
    end
  end

  manager_salaries = employees.collect_filtered(
    filter: -> (e) { e.manager? },
    mapping: -> (e) { e.salary }
  )

I've opted to use the proposed 2.0 syntax for lambdas for consistency
with the assumption of named parameters. This would be much less
readable without the named parameters. This solves the efficiency
problem, but does it really retain the readability of either the
inefficient select/collect implementation or the list comprehension?
I, personally, don't think so.

I hope you've enjoyed this little detour through my thought process...

Jacob Fugal

···

On 8/10/05, Ben Giddings <bg-rubytalk@infofiend.com> wrote:

On Aug 4, 2005, at 13:20, Jeff Wood wrote:
> But still, you can see that the python syntax is quite a bit more
> readable ( at least in this case ).

I completely disagree. "item for item in items if item"? How is
that easy to understand?

And mostly like the ";" at the end of every line that we don't ever write :wink:
just like ";", and like () around arguments to methods, afaict

Regarding ";": Each statement *does* have an explicit terminator. It's
just that there are two choices for terminator: ";" or newline.

Regarding "()": This is somewhat different. Anytime you have a block
of code, you're for sure explicitly marking the beginning ("def",
"class", "module", "do"). Making the beginning explicit but the
terminator implicit would be like making the closing paren optional
when using an open paren.

But as was already pointed out this seem to be non obvious, and thus it
is probably a bad idea.

Yes, IMNSHO it is a *very* bad idea[1]. Even worse than significant
whitespace. :wink:

Jacob Fugal

[1] Remember though, it's just this idea I'm ragging on. I've liked
many of your other ideas!

···

On 8/5/05, gabriele renzi <surrender_it@remove-yahoo.it> wrote:

And yet another troll on tabs vs. spaces ...

I'll definitely avoid using any language whose behaviour depends on the
editor used and/or its configuration.

Sylvain

The single advantage of "hard tabs" is to save disk space, IMO.

True, although with todays large hard drives, it's not paramount. It
think if the size-ratio of tabs to spaces were fixed (say, at the
compromise of 4, between 2 and 8) then I think tabs would be great.
Unfortunately as it stands, it's better to use spaces --they're
universally the same.

T.

gabriele renzi <surrender_it@remove-yahoo.it> writes:

well, if I write

def foozer(x):
  if x >10:
   print x
  do other stuff

and I do comment out the "if" line, there is a syntax error

Uh, this is much less of a problem with indentation-based
syntax than with delimiter-based such.

   def foozer(x)
     if x > 10
       print x
     end
     do other stuff
   end

Comment out the `if' line in the above code and you still
get a syntax error, but on a different line!

In general, with indentation-based syntax, what you see is
what you get, while with delimiter-based syntax, what you
see might or might not be what you get.

···

--
Daniel Brockman <daniel@brockman.se>