invasive parameters as method mode variables

T

Trans

Working on a method where I would like one part of it's operations to
be optional. Here's the crux of the code:

def parse_multicommand( line=nil, arity={} )
argv = parse_line(line)
argv = multi_flag(argv) # optional?

# ...
end

I would prefer not to add another parameter to the method signiture to
signify this option b/c its rare and it would complexify the call to
much, especially if there is more than one optional part --which is
possible. But other tahn that I don't have much choice, I'll probably
have to create an extra method called
#parse_multicommand_without_multi_flag. Yuk!

Not that helps me presently, but this did get me to thinking of using a
"global" flag that can be set external to the method. That would work
but it wouldn't be thread safe. Then it occured to me the
Binding.of_caller could be helpful here. Using the Binding#[] extension
for local variable access:

def parse_multicommand( line=nil, arity={} )
argv = parse_line(line)
argv = multi_flag(argv) unless Binding.of_caller[:no_multi_flag]

# ...
end

Then to use:

no_multi_flag = true
parse_multicommand( line )

I know this breaks the whole idea of function encapsulation, but it has
it's advantages in certain cases like mine. It also might be of usedin
a few other places like String#each's separator. So that got me to
thinking of a cleaner way to provided this capability of invasive
parameters as "method mode variables".

def parse_multicommand( line=nil, arity={} )
argv = parse_line(line)
argv = multi_flag(argv) unless --no_multi_flag

# ...
end

# '--' indicates a method mode variable
--no_multi_mode = true
parse_multicommand( line )

Thouhgts?

T.
 
J

James Edward Gray II

Thouhgts?

My thoughts on your current suggestion: Yuck. You really want this
to become so common that the language itself supports it? I
definitely don't. The whole usage case is a code smell, in my opinion.

My thoughts on your suggestions in general: You sure spend a lot of
time trying to rewrite Ruby's syntax. ;)

James Edward Gray II
 
A

ara.t.howard

Working on a method where I would like one part of it's operations to
be optional. Here's the crux of the code:

def parse_multicommand( line=nil, arity={} )
argv = parse_line(line)
argv = multi_flag(argv) # optional?

# ...
end

I would prefer not to add another parameter to the method signiture to
signify this option b/c its rare and it would complexify the call to
much, especially if there is more than one optional part --which is
possible. But other tahn that I don't have much choice, I'll probably
have to create an extra method called
#parse_multicommand_without_multi_flag. Yuk!

Not that helps me presently, but this did get me to thinking of using a
"global" flag that can be set external to the method. That would work
but it wouldn't be thread safe. Then it occured to me the
Binding.of_caller could be helpful here. Using the Binding#[] extension
for local variable access:

def parse_multicommand( line=nil, arity={} )
argv = parse_line(line)
argv = multi_flag(argv) unless Binding.of_caller[:no_multi_flag]

# ...
end

Then to use:

no_multi_flag = true
parse_multicommand( line )

I know this breaks the whole idea of function encapsulation, but it has
it's advantages in certain cases like mine. It also might be of usedin
a few other places like String#each's separator. So that got me to
thinking of a cleaner way to provided this capability of invasive
parameters as "method mode variables".

def parse_multicommand( line=nil, arity={} )
argv = parse_line(line)
argv = multi_flag(argv) unless --no_multi_flag

# ...
end

# '--' indicates a method mode variable
--no_multi_mode = true
parse_multicommand( line )

Thouhgts?

method + state => object

harp:~ > cat a.rb
require 'rubygems'
require 'attributes'

class Parser
attribute 'no_multi_flag'
def parse_multicommand
p [:parse_multicommand, no_multi_flag]
end
def parsing &b
instance_eval &b
end
end

parser = Parser.new

parser.parsing{
no_multi_flag true
parse_multicommand
}


harp:~ > ruby a.rb
[:parse_multicommand, true]


fun to clean up with prototype:

harp:~ > cat a.rb
require 'rubygems'
require 'prototype'


parser = prototype{
no_multi_flag false

def parse_multicommand
p [:parse_multicommand, no_multi_flag]
end

def parsing &b
instance_eval &b
end
}


parser.parsing{
parse_multicommand
}

parser.parsing{
no_multi_flag true
parse_multicommand
}


harp:~ > ruby a.rb
[:parse_multicommand, false]
[:parse_multicommand, true]


regards.

-a
 
T

Trans

method + state => object

good point. though it moves me away from the simplicity of single call.
also i wonder about things like String#each. the global default for
separator is not really the ideal implementation, but #each can't be
made a class.

Thanks,
T.
 
T

Trans

James said:
My thoughts on your current suggestion: Yuck. You really want this
to become so common that the language itself supports it? I
definitely don't. The whole usage case is a code smell, in my opinion.

perhaps. just exploring the idea. certainly Binding.of_caller allows
this kind of thing more or less. and I think there are good occassions
to use Binding.of_caller. in this case the no_multi_key option would
rarely be used. so having to turn the whole thing into a class, as ara
suggests, for one (or two) uncommon parameter seems like overkill,
although maybe it is better to do so.

I did think of one other way it could be done, inspried by an idea _why
had long ago:

#

def no_multi_flag
class << self
def multi_flag(argv); argv; end
end
yield
class << self
undef_method :multi_flag
end
end

though that sort of smells worse in my opinion.
My thoughts on your suggestions in general: You sure spend a lot of
time trying to rewrite Ruby's syntax. ;)

I know. It's sort or a hobby of mine. I have a general interest in
understanding the human <-> programming language interface.

T.
 
R

Robert Klemme

I would have put it differently: command pattern. Your method seems
pretty complex so you can change it into a command object. If the
problem at hand is complex then it probably needs a complex solution.
But I would not go down the metaprogramming route.
good point. though it moves me away from the simplicity of single call.
also i wonder about things like String#each. the global default for
separator is not really the ideal implementation, but #each can't be
made a class.
Really?
=> #<Enumerable::Enumerator:0x3a6b00>

Cheers

robert
 
D

David Vallner

--------------enigCCC5F293E92BC643933BA8A3
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
#each can't be made a class.
=20

Callable objects anyone?

(Yes, I've been too deep in the Python sugar bin recently :) Transparent
coroutines are prettiful.)

David Vallner


--------------enigCCC5F293E92BC643933BA8A3
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)

iD8DBQFFdzrCy6MhrS8astoRAhS1AJ9MGkEH+Xf25taqdqZ/Tb9Ba6FrwACePBgp
tQ81zicj9+EwpvPMfgKdpAM=
=SN57
-----END PGP SIGNATURE-----

--------------enigCCC5F293E92BC643933BA8A3--
 
T

Trans

Robert said:
I would have put it differently: command pattern. Your method seems
pretty complex so you can change it into a command object. If the
problem at hand is complex then it probably needs a complex solution.
But I would not go down the metaprogramming route.

=> #<Enumerable::Enumerator:0x3a6b00>

Sure. But I would think it preferable to just call str.each. Not have
to resort to Enumerators. Doing...

"this is a string".to_enum:)each, //).select { |c| ..

is less efficent and less readable (once you know what $/ is) then

$/ = // ; "this is a string".select { |c| ...

And if we can do it gloablly, which is not ideal, then why not do it
better with a local "method mode variable"?

Of course, I'm still not sure why it's such a bad idea to allow
Enumberable to pass thru a parameter to #each.

T.
 
L

Louis J Scoras

And if we can do it gloablly, which is not ideal, then why not do it
better with a local "method mode variable"?

Because you commit a gross violation of encapsulation for zero
increase in expressiveness? =)
 
T

Trans

Louis said:
Because you commit a gross violation of encapsulation for zero
increase in expressiveness? =)

The violation is much worse with a global var. With a local var the
violation is very minimal, plus the varaible can be specifically
designated as "method mode". So it's actually very similar to keyword
arguments. Eg.

each:)separator => //)

Just with a little extra flexability in that the method mode can apply
to multiple calls in the same local scope and the mode variable doesn't
have to intermingle with true data parameters.

As for expressiveness. I'm not sure how youre measuring that, the
to_enum version is clearly more convoluted (with exception of the $/
var, but that could be called $input_separator or some such name
instead too).

In anycase, perhaps any breakage of the local encapsulation is too
much, and matz will never grant us Binding.of_caller. But then why does
this global default on String#each persist?

T.
 
L

Louis J Scoras

The violation is much worse with a global var. With a local var the
violation is very minimal, plus the varaible can be specifically
designated as "method mode".

You are exactly right: it is _less_ of a violation. However, I think
this is the part where I'm supposed to mention something about a
``slippery slope.''
So it's actually very similar to keyword arguments. Eg.

each:)separator => //)

Just with a little extra flexability in that the method mode can apply
to multiple calls in the same local scope and the mode variable doesn't
have to intermingle with true data parameters.

Again, you are right, but why do this when you already have an
objects, whose entire reason for existence is to track state
information. Why not make it an honest to goodness part of the
interface?

enumerable.separator = //
# use each
As for expressiveness. I'm not sure how youre measuring that, the
to_enum version is clearly more convoluted (with exception of the $/
var, but that could be called $input_separator or some such name
instead too).

No, it's perfectly clear. What it lacks is concision, and while
concision is a desirable quality, it is not worth trading for clarity
and transparency. Saving a few keystrokes is not a good reason for
adding a new mechanism that acts at a distance.
In anycase, perhaps any breakage of the local encapsulation is too
much, and matz will never grant us Binding.of_caller. But then why does
this global default on String#each persist?

I can't offer much insight on that, but I'd suspect it's historical.
 
T

Trans

Louis said:
You are exactly right: it is _less_ of a violation. However, I think
this is the part where I'm supposed to mention something about a
``slippery slope.''

:) point taken.
No, it's perfectly clear. What it lacks is concision, and while
concision is a desirable quality, it is not worth trading for clarity
and transparency. Saving a few keystrokes is not a good reason for
adding a new mechanism that acts at a distance.

Well, "perfectly" is certainly overstating but I take you point.
However, it's not just keystrokes. Have to create a new Enumerator
object is also much less efficient.
I can't offer much insight on that, but I'd suspect it's historical.

I had talked to matz about it once, and he essentially said he didn't
want it for simplicity sake. I can;t say I quite understand that, but
there it is. hoever you just helped me release taht in 1.9+ the
situation is at least improved b/c

"string".each(//) #=> enumerator

Still less efficent but at least concise. And the global default can go
away.

T.
 
T

Trans

Peña said:
:From => "Trans [mailto:[email protected]]"
# each:)separator => //)

hmm, interesting. ' seems my mind likes that style. sometimes i'd wish #each can receive a param, so i don't have to remember all those each_* and #to_enum thingies. That would mean i could do something like the ff

each:)char)
each:)byte)
each:)with_index)
each:)separator => /\s/)
each:)separator => ":")

?

quite. it seems matz doesn't care for symobolic paramters of this kind.
once i even asked him about a special case modification in arg
interpretation and precedence so we could do things like:

each:char
each:byte
each:with_index
each:byte:with_index

matz didn't like. i think i can understand, there are pros and cons.
the important con is it would make subclassing and overriding a method
more difficult.

(OT) he also said he had a different idea for using ':' in a method
name. other then :after and :back i wonder what it is and if it has
some general application?

t.
 
L

Louis J Scoras

Well, "perfectly" is certainly overstating but I take you point.
However, it's not just keystrokes. Have to create a new Enumerator
object is also much less efficient.

Busted. You'll have to forgive me that small rhetorical flourish =)

What I meant to say is that the semantics of Enumerator aren't very
hard to understand. Indeed it does induce some overhead, but I don't
think it is in any way "convoluted".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top