flip flop operator and assignment

P

Phil Tomson

I'm working on the pattern matching section for
http://pleac.sourceforge.net/pleac_ruby/t1.html (an attempt to duplicate
the Perl Cookbook for several languages including Ruby).

The Perl code that needs to be duplicated in Ruby is:
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof();
}


In Ruby first I tried:

File.open("filename"){|f|
f.each_line {|l|
in_header = $.==1 .. l=~/^$/
in_body = l=~/^$/ .. f.eof
puts "in_header: #{l}" if in_header
puts "in_body: #{l}" if in_body
}
}

But that give the following error:
ArgumentError: bad value for range

However, when I changed it to use the ternary operator, like so:

File.open("filename"){|f|
f.each_line {|l|
in_header = $.==1 .. l=~/^$/ ? true : false
in_body = l=~/^$/ .. f.eof ? true : false
puts "in_header: #{l}" if in_header
puts "in_body: #{l}" if in_body
}
}

It then works.

What gives? It seems that the flip/flop operator is evaluating to true or
false, why can't I just assign that value to in_header or in_body?

Phil
 
T

ts

P> in_header = $.==1 .. l=~/^$/

this is not the flip flop operator, but the range operator : this is why
it give an error

P> in_header = $.==1 .. l=~/^$/ ? true : false

this is the flip flop operator


Guy Decoux
 
P

Phil Tomson

P> in_header = $.==1 .. l=~/^$/

this is not the flip flop operator, but the range operator : this is why
it give an error

P> in_header = $.==1 .. l=~/^$/ ? true : false

this is the flip flop operator

Yes, I figured that it was being interpreted that way, but my question is
why?

this part:
$.==1 .. l=~/^$/

is the same in both statements. Why does it get interpreted as a range in
one case, and a flip flop in the other?

I could see that if I did: ($.==1 .. l=~/^$/) that the interpreter could
get the idea that it's a range, but it would be a range like this:
(false..true) or (true..false) because $.==1 has to evaluate to either
true or false. If I try either one of these in irb I get:

(true..false)
ArgumentError: bad value for range

(false..true)
ArgumentError: bad value for range

so it appears that you can't have a range of TrueClass, FalseClass
therefore why doesn't the interpreter think it's a flip/flop operator?

Phil
 
T

ts

P> Yes, I figured that it was being interpreted that way, but my question is
P> why?

ruby use `..' for the range operator and the flip-flop operator.

When it see `..' in a condition, it transform the range operator into the
flip-flop operator.

a .. b # range operator
a .. b?true:false # flip-flop operator
if a .. b; end # flip-flop operator


Guy Decoux
 
J

Jamis Buck

ts said:
P> Yes, I figured that it was being interpreted that way, but my question is
P> why?

ruby use `..' for the range operator and the flip-flop operator.

Reading the posts in this discussion has been very enlightening for me.
I finally understand the flip-flop operator, for one thing. And I think
I understand the root of the "dislike" some people have for the
flip-flop: it uses the same syntax as a completely unrelated (and
possibly more common) concept, which can make the intuitive leap a bit hard.

I can certainly see the value in the flip-flop, and where I was
originally on the "team" that was rooting for its removal, I now would
like to see it remain, but in different form. What if it used a
different syntax, but the same semantics? This would allow the
flip-flop to be used outside of conditionals, too, since there would be
no ambiguity involved.

So, instead of '..' and '...', how about something completely new, like
perhaps '--', or '~~'? Or even a new keyword, like 'flip' or
'flipflop'? It would be nice to also somehow provide a way to access
some underlying objectified represention of the flip-flop, so that its
state could be queried and manipulated,

My $0.02.

- Jamis
 
N

nobu.nokada

Hi,

At Tue, 3 Feb 2004 13:08:50 +0900,
Jamis said:
So, instead of '..' and '...', how about something completely new, like
perhaps '--', or '~~'? Or even a new keyword, like 'flip' or
'flipflop'? It would be nice to also somehow provide a way to access
some underlying objectified represention of the flip-flop, so that its
state could be queried and manipulated,

Ruby already has both of unary and binary '-' operators, so the
former will conflict. But '~' operator is only unary now, the
later wouldn't.
 
J

Jamis Buck

Hi,

At Tue, 3 Feb 2004 13:08:50 +0900,
Jamis Buck wrote:



Ruby already has both of unary and binary '-' operators, so the
former will conflict. But '~' operator is only unary now, the
later wouldn't.
Good point. Another option would be to retain the use of the '..' and
'...', but prefix any flip-flop expression with some disambiguating
operator or keyword, a la:

a .. b #-> range
flip a..b # -> flip-flop

With that, you could then add another piece of syntax to obtain the
internal "objectified" representation:

flip a..b => c

The expression would still return boolean, as the regular flip-flop, but
would assign the object to 'c', which could then be manipulated and queried:

current_value = c.get_state
c.set_state( false )

- Jamis
 
P

Phil Tomson

Jamis Buck said:
Reading the posts in this discussion has been very enlightening for me.
I finally understand the flip-flop operator, for one thing. And I think
I understand the root of the "dislike" some people have for the
flip-flop: it uses the same syntax as a completely unrelated (and
possibly more common) concept, which can make the intuitive leap a bit hard.

I can certainly see the value in the flip-flop, and where I was
originally on the "team" that was rooting for its removal, I now would
like to see it remain, but in different form. What if it used a
different syntax, but the same semantics? This would allow the
flip-flop to be used outside of conditionals, too, since there would be
no ambiguity involved.

So, instead of '..' and '...', how about something completely new, like
perhaps '--', or '~~'? Or even a new keyword, like 'flip' or
'flipflop'? It would be nice to also somehow provide a way to access
some underlying objectified represention of the flip-flop, so that its
state could be queried and manipulated,

-- would look too much like decrement (from the perspective of other
languages) so that could also be confusing. ~~ might be better.

'flipflop' is the object, not the action and in this case it seems
like you're basically trying to say:

"do something from the time condition A becomes true until the time
condition B becomes true". Perhaps, as you say, a new keyword is in
order. But what if we could make use of an existing keyword; I'm
thinking that 'until' might work. It would look something like:

if l=~/BEGIN/ until l=~/END/ do
#do something in this range
end

Actually, I don't think 'until' is really a keyword (correct me if I'm
wrong), but that it's actually a buit-in method that takes a block, so
it might be difficult to coerce it into this proposed usage.

Another idea would be to have a 'from (condition) to (condition)'
statement that looks looks like:
from l=~/BEGIN/ to l=~/END/ do
#do something in this range
end

Then we just need some way to determine if the range is inclusive or
exclusive...
from l=~/BEGIN/ to l=~/END/ inclusive do
puts l
end

#prints:
BEGIN
foo
bar
END

from l=~/BEGIN/ to l=~/END/ exclusive do
puts l
end

#prints:
foo
bar

....but maybe there's a better way to do that. Also, how do you get
the same kind of behavioral differences that we see with the current
... and ... flip flop operators?

It seems like the 'from (condition) to (condition)' statement could
also return the underlying flip/flop object, kind of like [] returns
an Array or {} returns a Hash. So there could still be a FlipFlop
class, but this would just be a shortcut that keeps you from having to
instantiate a FlipFlop object explicitly prior to use.

ff = from l=~/BEGIN/ to l=~/END/ { ... }
OR:
from l=~/BEGIN/ to l=~/END/ {|ff| ... }

then you could call methods on the ff object, like:
ff.status? (true or false)
ff.class #=> FlipFlop

I'm just sort of brainstorming here, but I think the 'from .. to ..
{}' statement is very readable and the intent is quite clear and it
just might be able to replace the current flipflop operators.

Phil
 
J

Joel VanderWerf

Phil said:
-- would look too much like decrement (from the perspective of other
languages) so that could also be confusing. ~~ might be better.

'flipflop' is the object, not the action and in this case it seems
like you're basically trying to say:

"do something from the time condition A becomes true until the time
condition B becomes true". Perhaps, as you say, a new keyword is in
order. But what if we could make use of an existing keyword; I'm
thinking that 'until' might work. It would look something like:

if l=~/BEGIN/ until l=~/END/ do
#do something in this range
end

Actually, I don't think 'until' is really a keyword (correct me if I'm
wrong), but that it's actually a buit-in method that takes a block, so
it might be difficult to coerce it into this proposed usage.

It's a kewyword:

irb(main):001:0> until(1) {}
irb(main):002:1> end
SyntaxError: compile error
(irb):1: parse error
until(1) {}
^
from (irb):2
Another idea would be to have a 'from (condition) to (condition)'
statement that looks looks like:
from l=~/BEGIN/ to l=~/END/ do
#do something in this range
end

Then we just need some way to determine if the range is inclusive or
exclusive...
from l=~/BEGIN/ to l=~/END/ inclusive do
puts l
end

#prints:
BEGIN
foo
bar
END

from l=~/BEGIN/ to l=~/END/ exclusive do
puts l
end

Very readable! It may be an improvement that the flipflop isn't being
used with if, but with a special keyword. The hidden state bothers me
less that way. Of course you lose the possibility of a condition with
more complex logic.
 
P

Phil Tomson

Joel VanderWerf said:
Very readable! It may be an improvement that the flipflop isn't being
used with if, but with a special keyword. The hidden state bothers me
less that way. Of course you lose the possibility of a condition with
more complex logic.

Couldn't you just use the returned FlipFlop object for those purposes?

ff = from l=~/BEGIN/ to l=~/END/ #no block passed in

then you could do things with ff:
if ff.set?
#do something
else
#do something else
end

The from (condition) to (condition) would just be syntactic sugar for
the creation of a FlipFlop object. (kind of like [] is for Array and
{} is for Hash, or lamda is for Proc). Come to think of it, couldn't
ff be a functional object, kind of like a closure (Proc)? Actually,
it's probably more like a set of conditions that a Proc must evaluate
when it (the block being passed in to the from .. to .. ) is called.

....just thinking out loud. Should probably try to prototype something
that doesn't require any syntax changes.

Phil
 
J

Jamis Buck

Phil said:
Another idea would be to have a 'from (condition) to (condition)'
statement that looks looks like:
from l=~/BEGIN/ to l=~/END/ do
#do something in this range
end

What if we just use the keyword 'in' to introduce a flipflop, and retain
the range-ish syntax to separate the conditions? Something like this:

if in l=~/BEGIN/ .. l=~/END/
...
end

The advantage of using a boolean phrase is that you can use it in
conditions, where it is most common. That also lets you do something
when the flipflop is false, which the 'from..do' construct you suggested
doesn't (easily) allow.

Since getting at the object that encapsulates the state of the flipflop
will be less common (one might even say "rare", although its hard to say
at this point since neither Perl nor Ruby allow it), the common case
(just getting the boolean result) should be simple and straightforward.
Getting at the object might be done via something like this:

in l=~/BEGIN/ .. l=~/END/ => state

The expression itself still returns boolean, but the object
encapsulating the flipflop is placed in 'state'.

I took the 1.8.1 source and tried hacking at it to introduce this
syntax, and managed to get the 'in' keyword working as above. Problem
is, I'm not a bison expert, and I'm certainly not very familiar with the
inner workings of Ruby's parser, so I keep getting 2 reduce/reduce
conflicts caused by the 'in' keyword... not sure how to fix that. And
when I try to use '=>' to assign the object, I get 27 shift/reduce
conflicts (which I think I understand, but I'm not sure how to fix).
I'd be happy to send a patch to anyone interested, but it's really
pretty trivial, and (as I said) imperfect.

I tried introducing new keywords to fill these roles, but the means by
which Ruby does its keyword lookup is pretty arcane, and it is not
immediately obvious how to add a new keyword. Any gurus of Ruby's inner
workings that could clarify how to do this?

I'd be especially interested in hearing from the proponents of the
flip-flop operator in Ruby as to whether this suggestion would "fit the
bill." If it isn't something they'd be comfortable using, then it is
probably not the most appropriate solution to the problem. However, I
think it gets the best of both worlds -- it is clearer that you're
dealing with more than just a range, and you can use it in more places
than simply in conditions.
I'm just sort of brainstorming here, but I think the 'from .. to ..
{}' statement is very readable and the intent is quite clear and it
just might be able to replace the current flipflop operators.

I agree, 'from .. to ...' is very readable, but perhaps not as
convenient given the regular usage of the flip-flop operator. Then
again, I'd like to hear from someone who uses the flip-flop a lot as to
whether they feel it would be cumbersome. Readability is good, but if
you take it too far you get VB and Pascal, which are easy to learn, but
clunky (IMO) to actually write software in.
 
N

nobu.nokada

Hi,

At Wed, 4 Feb 2004 09:21:49 +0900,
Jamis said:
What if we just use the keyword 'in' to introduce a flipflop, and retain
the range-ish syntax to separate the conditions? Something like this:

if in l=~/BEGIN/ .. l=~/END/
...
end

The advantage of using a boolean phrase is that you can use it in
conditions, where it is most common. That also lets you do something
when the flipflop is false, which the 'from..do' construct you suggested
doesn't (easily) allow.

Agreed, and it seems easy to implement.
Since getting at the object that encapsulates the state of the flipflop
will be less common (one might even say "rare", although its hard to say
at this point since neither Perl nor Ruby allow it), the common case
(just getting the boolean result) should be simple and straightforward.
Getting at the object might be done via something like this:

in l=~/BEGIN/ .. l=~/END/ => state

The expression itself still returns boolean, but the object
encapsulating the flipflop is placed in 'state'.

How will you use it, in other words, how and when it will be
changed?


Index: node.h
===================================================================
RCS file: /cvs/ruby/src/ruby/node.h,v
retrieving revision 1.52
diff -u -2 -p -d -r1.52 node.h
--- node.h 22 Jan 2004 08:31:33 -0000 1.52
+++ node.h 4 Feb 2004 00:53:13 -0000
@@ -327,4 +327,6 @@ typedef struct RNode {
#define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0)
#define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0)
+#define NEW_FLIP2(b,e) NEW_NODE(NODE_FLIP2,b,e,local_append(internal_id()))
+#define NEW_FLIP3(b,e) NEW_NODE(NODE_FLIP3,b,e,local_append(internal_id()))
#define NEW_ATTRSET(a) NEW_NODE(NODE_ATTRSET,a,0,0)
#define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0)
Index: parse.y
===================================================================
RCS file: /cvs/ruby/src/ruby/parse.y,v
retrieving revision 1.315
diff -u -2 -p -d -r1.315 parse.y
--- parse.y 3 Feb 2004 02:23:20 -0000 1.315
+++ parse.y 4 Feb 2004 00:53:13 -0000
@@ -619,4 +619,12 @@ expr : command_call
$$ = NEW_NOT(cond($2));
}
+ | kIN arg tDOT2 arg
+ {
+ $$ = NEW_FLIP2($2, $4);
+ }
+ | kIN arg tDOT3 arg
+ {
+ $$ = NEW_FLIP3($2, $4);
+ }
| arg
;
 
P

Phil Tomson

What if we just use the keyword 'in' to introduce a flipflop, and retain
the range-ish syntax to separate the conditions? Something like this:

if in l=~/BEGIN/ .. l=~/END/
...
end

The advantage of using a boolean phrase is that you can use it in
conditions, where it is most common. That also lets you do something
when the flipflop is false, which the 'from..do' construct you suggested
doesn't (easily) allow.

Since getting at the object that encapsulates the state of the flipflop
will be less common (one might even say "rare", although its hard to say
at this point since neither Perl nor Ruby allow it), the common case
(just getting the boolean result) should be simple and straightforward.
Getting at the object might be done via something like this:

in l=~/BEGIN/ .. l=~/END/ => state

I agree, 'from .. to ...' is very readable, but perhaps not as
convenient given the regular usage of the flip-flop operator. Then
again, I'd like to hear from someone who uses the flip-flop a lot as to
whether they feel it would be cumbersome. Readability is good, but if
you take it too far you get VB and Pascal, which are easy to learn, but
clunky (IMO) to actually write software in.

I use the flip-flop pretty commonly when I'm parsing files. For my usage,
the from..to.. would probably work fine:

#not a real example, of course
File.foreach{|l|
from l=~/BEGIN/ to /END/ do
#nesting should work ok
from l=~/def/ to /end/ do
#method definition
end
from l=~/from/ to /end/ do
#proposed syntax, parse thyself
end
end
#would we need elsfrom?
from l=~/<html>/i to l=~/</\html>/i
#in an HTML file
end
}

But others have suggested that they use the flipflop for other things. I
think that if the from construct returns a FlipFLop object that it would
be useable for these other appliations as well, but I'd like to hear some
other suggestions.

Maybe the from..to.. construct should just return a boolean, then it would
be used with an if statement like:

if from (condition) to (condition)

But using 'from' could still be slanted more toward the file parsing
application, rather than a more general purpose usage. I thought of
'from' because that's the main way I use the flip/flop operator.

BTW: I really don't like the 'flip' idea:

if flip (condition) to (condition)

because it's not clear from reading it what 'flip' means.

Phil
 
J

Jamis Buck

Hi,

At Wed, 4 Feb 2004 09:21:49 +0900,
Jamis Buck wrote:



Agreed, and it seems easy to implement.

As evidenced by your patch. Thanks!
How will you use it, in other words, how and when it will be
changed?

I suggested this primarily because there were a few posters that
mentioned the fact that the "hidden state" aspect of the flip-flop op
turned them off from the whole concept. By exposing the state, it makes
it less "mysterious". However, I'll give a very contrived example of
where it might be useful. Suppose you had an input file that contained
the following:

BEGIN
1
2
special
3
END

In general, you want a parser that extracts everything between BEGIN and
END, but there are a few cases where you want to treat the word
'special' as the end instead, and then ignore everything until the next
BEGIN.

while line = file.gets
if in line=~/BEGIN/ .. line=~/END/ => state
state.set_state( line =~ /special/ )
if state.get_state
# process line
end
end
end

Like I said, it's pretty contrived, and would be better solved by
choosing smarter guard conditions. However, it demonstrates a situation
where exposing an interface for manipulating a flip-flop's state may be
useful.
 
N

nobu.nokada

Hi,

At Wed, 4 Feb 2004 15:23:10 +0900,
Jamis Buck wrote in [ruby-talk:91521]:
In general, you want a parser that extracts everything between BEGIN and
END, but there are a few cases where you want to treat the word
'special' as the end instead, and then ignore everything until the next
BEGIN.

while line = file.gets
if in line=~/BEGIN/ .. line=~/END/ => state
state.set_state( line =~ /special/ )
if state.get_state
# process line
end
end
end

Will set_state turn the state true, or false? Seeing the next
line, set_state(true) makes get_state to return false...
Like I said, it's pretty contrived, and would be better solved by
choosing smarter guard conditions. However, it demonstrates a situation
where exposing an interface for manipulating a flip-flop's state may be
useful.

Rather, what about binding a flip-flop operator to a local
variable?

$ ./ruby -e 'while l = gets; if in /BEGIN/=~l .. /END/=~l => last; p [l, last]; last = /special/!~l end; end'
xx
BEGIN
["BEGIN\n", true]
xxx
["xxx\n", true]
special
["special\n", true]
dsfa
ffdf
END
xxx
BEGIN
["BEGIN\n", true]
xxx
["xxx\n", true]
END
["END\n", false]


Index: node.h
===================================================================
RCS file: /cvs/ruby/src/ruby/node.h,v
retrieving revision 1.52
diff -u -2 -p -d -r1.52 node.h
--- node.h 22 Jan 2004 08:31:33 -0000 1.52
+++ node.h 4 Feb 2004 06:37:48 -0000
@@ -327,4 +327,6 @@ typedef struct RNode {
#define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0)
#define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0)
+#define NEW_FLIP2(b,e,v) NEW_NODE(NODE_FLIP2,b,e,v)
+#define NEW_FLIP3(b,e,v) NEW_NODE(NODE_FLIP3,b,e,v)
#define NEW_ATTRSET(a) NEW_NODE(NODE_ATTRSET,a,0,0)
#define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0)
Index: parse.y
===================================================================
RCS file: /cvs/ruby/src/ruby/parse.y,v
retrieving revision 1.315
diff -u -2 -p -d -r1.315 parse.y
--- parse.y 3 Feb 2004 02:23:20 -0000 1.315
+++ parse.y 4 Feb 2004 06:49:09 -0000
@@ -266,5 +266,5 @@ static void top_local_setup();
%type <id> fitem variable sym symbol operation operation2 operation3
%type <id> cname fname op f_rest_arg
-%type <num> f_norm_arg f_arg
+%type <num> f_norm_arg f_arg flip_var
%token tUPLUS /* unary+ */
%token tUMINUS /* unary- */
@@ -279,4 +279,5 @@ static void top_local_setup();
%token tMATCH tNMATCH /* =~ and !~ */
%token tDOT2 tDOT3 /* .. and ... */
+%token tFLIP2 tFLIP3 /* ~~ and ~~~ */
%token tAREF tASET /* [] and []= */
%token tLSHFT tRSHFT /* << and >> */
@@ -311,4 +312,5 @@ static void top_local_setup();
%right '?' ':'
%nonassoc tDOT2 tDOT3
+%nonassoc tFLIP2 tFLIP3
%left tOROP
%left tANDOP
@@ -602,4 +604,16 @@ stmt : kALIAS fitem {lex_state = EXPR_F
;

+flip_var : tASSOC tIDENTIFIER
+ {
+ if (!is_local_id($2))
+ yyerror("flip-flop variable must be local variable");
+ $$ = local_cnt($2);
+ }
+ | none
+ {
+ $$ = local_append(internal_id());
+ }
+ ;
+
expr : command_call
| expr kAND expr
@@ -619,4 +633,16 @@ expr : command_call
$$ = NEW_NOT(cond($2));
}
+ | kIN arg tDOT2 arg flip_var
+ {
+ value_expr($2);
+ value_expr($4);
+ $$ = NEW_FLIP2($2, $4, $5);
+ }
+ | kIN arg tDOT3 arg flip_var
+ {
+ value_expr($2);
+ value_expr($4);
+ $$ = NEW_FLIP3($2, $4, $5);
+ }
| arg
;
@@ -1069,4 +1095,16 @@ arg : lhs '=' arg
$$ = NEW_DOT3($1, $3);
}
+ | arg tFLIP2 arg
+ {
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_FLIP2($1, $3, local_append(internal_id()));
+ }
+ | arg tFLIP3 arg
+ {
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_FLIP3($1, $3, local_append(internal_id()));
+ }
| arg '+' arg
{
@@ -4038,4 +4076,10 @@ yylex()
pushback(c);
}
+ }
+ else if (peek('~')) {
+ nextc();
+ if (!peek('~')) return tFLIP2;
+ nextc();
+ return tFLIP3;
}
switch (lex_state) {
 
J

Jamis Buck

Hi,

At Wed, 4 Feb 2004 15:23:10 +0900,
Jamis Buck wrote in [ruby-talk:91521]:

In general, you want a parser that extracts everything between BEGIN and
END, but there are a few cases where you want to treat the word
'special' as the end instead, and then ignore everything until the next
BEGIN.

while line = file.gets
if in line=~/BEGIN/ .. line=~/END/ => state
state.set_state( line =~ /special/ )
if state.get_state
# process line
end
end
end

Will set_state turn the state true, or false? Seeing the next
line, set_state(true) makes get_state to return false...

Well, what I had envisioned was the following:

FlipFlip#get_state: return the current truth value of the flip flop.
FlipFlop#set_state( state ): set the truth value of the flip flop

And you're right -- there's a typo in my example. :( The set_state call
should be:

state.set_state( line !~ /special/ )
Rather, what about binding a flip-flop operator to a local
variable?

Fascinating concept--that would certainly be simpler. The only benefit
I can see to using an object as opposed to a local variable binding is
that you could pass the flipflop object into a method and have any
manipulations made on it in the method be effective outside the method.
 

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

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top