Yielding an object and caring about the result: the cousin of Object#tap

2007/11/14, [email protected] [email protected]:

}
}.as { |data_files|
add_suffixes(source_files + add_prefixes(data_files))
}.map { |basename|
File.join dir, basename
}

(BTW ‘suffix’ here means the chars right before the dot; after the dot
I call the extension.)

Why do add_suffixes and add_prefixes have to be methods that work on a
collection instead of a single item? Do they modify the collection in
any way or do they need information from other entries to do their
work on a single entry?

If not, I would change that and then you could do this:

all_files = (
source_files +
stems.map {|stem| add_prefix “#{ stem }.#{ guess_extension stem }”}
).map {|name| File.join dir, add_suffix(name)}

This is still pretty complex (but the algorithm is anyway) and you do
not need any temporaries outside of block parameters. Also,
add_suffix and add_prefix will be relieved from iterating collections
and can be focussed on doing one thing properly.

Kind regards

robert

On Nov 14, 2007, at 10:10 AM, [email protected] wrote:

Please, could we resist the temptation to change the example code
based upon assumptions about the given input and methods? Such
pursuits are not at all relevant.

Is it possible for you to give us a real example, that functions as
intended and is complete in code, that isn’t subject to such
refactorings? Maybe that would help us focus on the question at hand.

James Edward G. II

On Nov 14, 9:33 am, Robert K. [email protected] wrote:

Why do add_suffixes and add_prefixes have to be methods that work on a
collection instead of a single item? Do they modify the collection in
any way or do they need information from other entries to do their
work on a single entry?

add_prefixes and add_suffixes examine the array; they cannot be
optimized by acting on a single element instead. I previously called
them transform1 and transform2 in order to emphasize that we can’t
assume anything about those methods.

A red herring was thrown into the discussion when I was chided for
calling them transform1 and transform2. Now that I’ve changed the
names, another red herring has emerged.

Please, could we resist the temptation to change the example code
based upon assumptions about the given input and methods? Such
pursuits are not at all relevant. This is what sidetracked the last
thread.

-FC

James Edward G. II wrote:

Please, could we resist the temptation to change the example code
based upon assumptions about the given input and methods? Such
pursuits are not at all relevant.

Is it possible for you to give us a real example, that functions as
intended and is complete in code, that isn’t subject to such
refactorings? Maybe that would help us focus on the question at hand.

But you can always refactor code to fit a particular style. FC wants
to talk about the usefulness of Object#as in functional-style code and
Robert insists that Object#as is not needed in imperative code. We
clearly have a cultural barrier with the 2 sides talking past each
other.

Daniel

On Nov 13, 3:25 pm, [email protected] wrote:

expanded = stems.map { |stem|
“#{ stem }.#{ guess_extension stem }”
}.as { |guesses|
transform2(source_files + transform1(guesses))
}.as { |basenames|
basenames.map { |basename|
File.join dir, basename
}
}

what the heck is wrong with

guesses = stems.map { |stem| “#{ stem }.#{ guess_extension
stem }” }
basenames = transform2(source_files + transform1(guesses))
expanded = basenames.map { |basename| File.join dir, basename }

or if you prefer

expanded = (
guesses = stems.map { |stem| “#{ stem }.#{ guess_extension
stem }” }
basenames = transform2(source_files + transform1(guesses))
basenames.map { |basename| File.join dir, basename }
)

T.

On Nov 14, 2007, at 8:57 PM, Daniel DeLorme wrote:

But you can always refactor code to fit a particular style. FC
wants to talk about the usefulness of Object#as in functional-style
code and Robert insists that Object#as is not needed in imperative
code. We clearly have a cultural barrier with the 2 sides talking
past each other.

this seems pretty close to the mark. i realized that, for me, #as
seems a bit too functional but, as i mentioned, i just need to use it
a bit to decide.

regards.

a @ http://codeforpeople.com/

On 15.11.2007 05:26, ara.t.howard wrote:

a bit to decide.
Interesting point although I am not sure whether #as is really
functional (and thus, whether Daniel’s remark is really close to the
mark). If I think of functional programming paradigm first item that
comes to mind is lack of side effects (other than IO probably). Here,
#as just enables method chaining in a single statement where you would
otherwise need multiple statements. From my point of view this is not
functional vs. non functional. In the end it’s mainly a question of
scoping: whether you need multiple local variables in the current scope
or can achieve the same with temporaries in nested and thus smaller
scopes. FC has stressed this point several times.

IMHO the (or at least: my) discussion was about the point that FC
claimed his solution with #as to be more readable than another solution
that used local variables for temporary values. So I tried to come up
with solutions that I consider more readable to be able to contrast
them with his approach. Note that I do not expect everybody to find
them equally readable since this is subject to personal preference and
habit.

Here is another approach that completely gets rid of temporaries without
needing #as:

all_files =
add_suffixes(source_files +
add_prefixes(
stems.map { |stem| “#{stem}.#{guess_extension stem}” }
)).map { |basename|
File.join dir, basename
}

If anything this seems more functional to me, since you have to read
inside out. :slight_smile: SCNR

Cheers

robert

On Nov 13, 2007 10:05 PM, -a [email protected] wrote:

for two reasons

  1. error reporting
  2. vars are cheap in ruby, function calls are not

although for simple/short code i do use the second often, reserving
the former for ‘real’ code i anticipate maintaining and debugging. i
suspect i’m in the minority here.

Me too, though that may be an ancient aversion to null pointers in
structure member dereferencing in C as in

some->null_pointer->in_the_middle->of_a_chain

I also find myself using this pattern:

if response = http.response # i.e. expecting nil or false on failure
response.foo
# etc.
else

end

Your point on avoiding unnecessary method calls is well-made - there’s
no telling how much an intermediate call may cost - why repeat it?

Regards,
Sean

On Nov 15, 3:04 pm, Robert K. [email protected] wrote:

}

If anything this seems more functional to me, since you have to read
inside out. :slight_smile: SCNR

Whether the function call syntax is prefix, infix, or postfix is
independent of whether it’s functional style or not. One reason I
like ruby is because I can be functional with postfix syntax. I
prefer reading block chains and method chains from beginning to end,
as opposed to prefix-syntax function calls from inside to outside.
Object#as allows me to keep the chain going when I am forced to use a
prefix syntax like File.basename().

I would also add that I make temporaries all the time. I do however
avoid re-assigning to the same temporary and, in most circumstances,
modifying the contents of a temporary (to be ditched when practical
concerns for efficiency are relevant).

-FC

2007/11/16, Sean O’Halpin [email protected]:

I also find myself using this pattern:

if response = http.response # i.e. expecting nil or false on failure
response.foo
# etc.
else

end

I seriously dislike the pattern above for the following reasons: it
can be easily misread as “if response == http.response” and there is
no need to have an assignment inside an if condition. In this case I
prefer an extra variable setter or using “and” if there is just one
statement:

response = http.response

if response

end

response = http.response and puts response

The situation is different with loops because there often this is the
most elegant solution:

while line = gets

end

Cheers

robert

On Nov 16, 2007, at 3:12 AM, Robert K. wrote:

response = http.response

if response

end

this just jumped into mind

unless [ response = http.response ].empty?
p response.body.size
end

i’ve never used that, but it’s kind of interesting…

a @ http://codeforpeople.com/

Hi –

On Sat, 17 Nov 2007, ara.t.howard wrote:

unless [ response = http.response ].empty?
p response.body.size
end

i’ve never used that, but it’s kind of interesting…

When would it ever be empty?

David

On Nov 15, 2007, at 1:05 PM, Robert K. wrote:

this point several times.
i guess it reminds of ‘let’ a little…

this sprang to mind:

cfp:~ > cat a.rb
class Object
def let *a, &b
Let.evaluate *a, &b
end

def as local, kvs = {}, &block
kvs.update local => self
Let.evaluate kvs, &block
end

class Let
instance_methods.each{|m| undef_method m unless m[%r/^__/]}

 Instance_eval = Object.instance_method :instance_eval
 Instance_variable_set =

Object.instance_method :instance_variable_set

 def self.evaluate kvs = {}, &block
   let = new
   singleton_class =
     class << let
       self
     end
   instance_eval = Instance_eval.bind let
   instance_variable_set = Instance_variable_set.bind let
   singleton_class.module_eval{ kvs.keys.each{|k| attr k} }
   instance_eval.call{ kvs.each{|k,v| instance_variable_set.call

“@#{ k }”, v} }
instance_eval.call &block
end
end
end

a = 40
b = 2
c = ‘forty-two’

p let(:x => a, :y => b){ x + y }

p a.as(:x){ x + b }

p a.as(:x, :y => b){ x + y }

fatal flaw

p let(:c => a, :d => b){ c + d }

cfp:~ > ruby a.rb
42
42
42
a.rb:44:in +': can't convert Fixnum into String (TypeError) from a.rb:44 from a.rb:27:in instance_eval’
from a.rb:27:in call' from a.rb:27:in evaluate’
from a.rb:3:in `let’
from a.rb:44

still - it’s kind of interesting…

a @ http://codeforpeople.com/

On Nov 16, 2007 10:12 AM, Robert K. [email protected]
wrote:

I seriously dislike the pattern above for the following reasons: it
can be easily misread as “if response == http.response” and there is
no need to have an assignment inside an if condition.

[snip]

The situation is different with loops because there often this is the
most elegant solution:

while line = gets

end

Well, I don’t really see the difference myself - but then I am
conditioned by C so I tend not to mix = and == up.
However, if you think it’s a little tricksy, then I’ll certainly
consider changing my practice. After all, code is written for other
people, not for yourself.

Regards,
Sean

use.inject do |as, often| as.you_can - without end

I do agree, but you know, that could be taken the wrong way (cf.
ruby-talk:277479 ff. :wink:

2007/11/16, ara.t.howard [email protected]:

end it’s mainly a question of scoping: whether you need multiple
def let *a, &b

   instance_eval = Instance_eval.bind let

a = 40
p let(:c => a, :d => b){ c + d }
from a.rb:27:in call' from a.rb:27:in evaluate’
from a.rb:3:in `let’
from a.rb:44

still - it’s kind of interesting…

Well, you could of course just do

$ ruby -e ‘def let;yield;end; let { x=10;y=20; puts x+y}’
30
$ ruby -e ‘x=10;y=20; puts x+y’
30

:slight_smile:

I guess “let” is in Ruby far less useful than in Lisp. :slight_smile:

Kind regards

robert

On Nov 16, 2:55 pm, “David A. Black” [email protected] wrote:

if response

When would it ever be empty?

David

sorry - through a compact in there…

personally i prefer the ‘=’ sign in there…