Project

General

Profile

Feature #5400

Remove flip-flops in 2.0

Added by judofyr (Magnus Holm) about 7 years ago. Updated 5 days ago.

Status:
Assigned
Priority:
Normal
Target version:
[ruby-core:39915]

Description

Nobody knows them. Nobody uses them. Let's just get rid of flip-flops, shall we?

Associated revisions

Revision bae638ad
Added by mame (Yusuke Endoh) 6 months ago

parse.y: Deprecate flip-flops

Ref #5400

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63667 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 63667
Added by mame (Yusuke Endoh) 6 months ago

parse.y: Deprecate flip-flops

Ref #5400

History

#1 [ruby-core:39919] Updated by yimutang (Joey Zhou) about 7 years ago

Magnus Holm wrote:

Nobody knows them. Nobody uses them. Let's just get rid of flip-flops, shall we?

I disagree. The flip-flop syntax is obscure, but very useful, especially in text manipulation.

For example, I want to fetch some chunks of lines :

DATA.each_line do |line|
  print line if (line =~ /begin/)..(line =~ /end/)
end

__END__
0a
1begin
2c
3end
4e
5f
6begin
7end
8i
9j

this will print:

1begin
2c
3end
6begin
7end

flip-flop syntax comes from Perl, the Perl idiom looks like "print if /begin/../end/;" or "print if 5..8;" (which means print line5 to line8).

Perl idiom is implicit, not so easy to read, Ruby idiom is a little hard to write.

I'm afraid Rudy didn't take advantage of flip-flops, I try to write in this way:

DATA.readlines.select {|line| (line =~ /begin/)..(line =~ /end/) } # error

it seems that ruby treat (line =~ /begin/)..(line =~ /end/) as a range object, that is not what I mean.

Maybe it's difficult for the parser to distinguish the range token ".." and flip-flop token "..", Perl use the same token because it has "context", but Ruby hasn't.

#2 [ruby-core:39925] Updated by yimutang (Joey Zhou) about 7 years ago

Magnus Holm wrote:

Nobody knows them. Nobody uses them. Let's just get rid of flip-flops, shall we?

Well, the flip-flop behavior is useful, so it should not be removed.

However, I agree that the syntax is a bit confusing.

Flip-flop in Ruby is not so powerful as in Perl (http://perldoc.perl.org/perlop.html#Range-Operators).

It seems like expression leading to true or false, but it cannot be assigned to a variable, and often be treated as a range literal.

So maybe we can get rid of the ".." syntax, instead, introduce a class to do the same thing.

I've implemented a simple class FlipFlop, which simulates the behavior of flip-flop in Perl.

class FlipFlop

  def initialize(test_right_same_time=false)
    @bool = false
    @sequence_num = 0
    @same_time = test_right_same_time
  end

  def rewind
    initialize(@same_time)
  end

  def test(condition_left,condition_right)
    if @bool == false and condition_left
      @sequence_num = 1
      @bool = true
      if @same_time == true and condition_right
        @sequence_num = 1.0
        @bool = false
      end
      return true
    elsif @bool == true and not condition_right
      @sequence_num += 1
      return true
    elsif @bool == true and condition_right
      @sequence_num += 1.0
      @bool = false
      return true
    else # @bool == false and condition_left == false
      @sequence_num = 0
      return false
    end
  end

  def true?
    @bool
  end

  def value
    @sequence_num
  end

  def end?
    @sequence_num.is_a? Float
  end

end
flipflop = FlipFlop.new

# take only line3 ~ line5 from a chunk of lines (from /begin/ to /end/)
lines = DATA.readlines.select do |line|
  t = flipflop.test(line =~ /begin/, line =~ /end/)
  t and flipflop.value.between?(3,5)
end

p lines # ["04end(x)\n", "09(x)\n", "10(x)\n", "11(x)\n", "17(x)\n", "18(x)\n", "19end(x)\n"]

__END__
01
02begin
03
04end(x)
05
06
07begin
08
09(x)
10(x)
11(x)
12end
13
14
15begin
16
17(x)
18(x)
19end(x)
20begin

#3 [ruby-core:39926] Updated by mame (Yusuke Endoh) about 7 years ago

Hello,
I'm one of the few users of flip-flop.

W, H = 44, 54
c = 7 + 42 * W
a = [0] * W * H
g = d = 0
f = proc do |n|
  a[c] += 1
  o = a.map {|z| " :#"[z, 1] * 2 }.join.scan(/.{#{W * 2}}/)
  puts "\f" + o.map {|l| l.rstrip }.join("\n")
  sleep 0.005
  d += 1 - 2 * ((g ^= 1 << n) >> n)
  c += [1, W, -1, -W][d %= 4]
end
1024.times do
  !!(!!(!!(!!(!!(!!(!!(!!(!!(true...
    f[0])...f[1])...f[2])...
    f[3])...f[4])...f[5])...
    f[6])...f[7])...f[8])
end

Sorry for off-topic :-)

I have no objection to deletion, but I'm just curious.
Why do you want to delete it aggressively?

--
Yusuke Endoh mame@tsg.ne.jp

#4 [ruby-core:40030] Updated by telemachus (Peter Aronoff) about 7 years ago

On Tue Oct 04 2011 @ 4:43, Magnus Holm wrote:

Nobody knows them. Nobody uses them. Let's just get rid of flip-flops,
shall we?

As someone who came to Ruby from Perl, I also use/like the flip-flop
operator.

Having said that, maybe a better question than "Who likes the feature?" or
"Who doesn't?" is "What's bad enough about flip-flop that merits removal?"
Does it cause some performance problem or lead to wrongheaded programming?
(Not rhetorical: I genuinely don't see what would make it worth removing.)

Thanks, Peter
--
[D]igital information lasts forever--or five years, whichever comes first.
"Ensuring the Longevity of Digital Information", Jeff Rothenberg

#5 [ruby-core:40043] Updated by agrimm (Andrew Grimm) about 7 years ago

I'll be a little sad if the flip flop operator is removed, but it is a Perlism, and Ruby is gradually getting rid of Perlisms. I suspect it won't be around in 100 years time, and I've heard that flip-flops aren't mentioned in the Ruby specification.

When I mentioned flip-flops (and Rubinius' failure to support them) in my talk at RubyKaigi 2011, the response of some was "What's the flip flop operator?"

If the feature is removed, how will Ruby treat existing code that uses the flip-flop operator?

Will it convert it into a literal range, and raise an ArgumentError? (false)..(true) raises an ArgumentError

Or will it explain that flip-flops are no longer supported?

#6 [ruby-core:40044] Updated by matz (Yukihiro Matsumoto) about 7 years ago

Hi,

Under the current plan, I am not going to remove flip-flop from 2.0,
since we are not going to made incompatible changes anytime soon. We
have to wait until 3.0.

                        matz.

#7 [ruby-core:40083] Updated by judofyr (Magnus Holm) about 7 years ago

I have no objection to deletion, but I'm just curious.
Why do you want to delete it aggressively?

--
Yusuke Endoh mame@tsg.ne.jp

I just want to get rid of complexity in the language.

Currently, flip-flops aren't well known for Rubyists, so I don't feel
comfortable of using them in code. I fear that it won't be readable.
And if you don't know them, it's easy to confuse them for literal
ranges, which makes it even more confusing. If it had a distinct
syntax, you would at least realize that you don't know about them, now
you would go "what? a Range literal is always true, no?".

#8 Updated by naruse (Yui NARUSE) about 7 years ago

  • Project changed from Ruby trunk to CommonRuby
  • Target version deleted (Next Major)

#9 Updated by naruse (Yui NARUSE) about 7 years ago

  • Project changed from CommonRuby to Ruby trunk

#10 [ruby-core:43722] Updated by mame (Yusuke Endoh) over 6 years ago

  • Target version set to Next Major

#11 [ruby-core:49501] Updated by Anonymous about 6 years ago

For Endo's sake, please don't remove this jewel, bring it to perfection, somehow :))))

#12 [ruby-core:52907] Updated by ko1 (Koichi Sasada) almost 6 years ago

  • Category set to core
  • Assignee set to matz (Yukihiro Matsumoto)

#13 [ruby-core:87119] Updated by nobu (Nobuyoshi Nakada) 7 months ago

judofyr (Magnus Holm) wrote:

Nobody knows them. Nobody uses them. Let's just get rid of flip-flops, shall we?

I know, and use them.

#14 [ruby-core:87120] Updated by matz (Yukihiro Matsumoto) 7 months ago

Finally, we are going to remove it. 2.6 will warn flip-flop usage of ranges.

Matz.

#15 [ruby-core:87498] Updated by mame (Yusuke Endoh) 6 months ago

  • Status changed from Open to Assigned

I've committed r63667..r63669 to deprecate flip-flips. I leave this ticket open to remove the feature in 3.0 (?).

There were some programs that used flip-flops in build scripts. I rewrote them to a code that does not use flip-flops. The work was harder than I expected.

Honestly I'm unsure if deprecation of flip-flops is really a right way...

#16 [ruby-core:89061] Updated by normalperson (Eric Wong) 3 months ago

mame@ruby-lang.org wrote:

There were some programs that used flip-flops in build
scripts. I rewrote them to a code that does not use
flip-flops. The work was harder than I expected.

Honestly I'm unsure if deprecation of flip-flops is really a right way...

https://bugs.ruby-lang.org/issues/5400#change-72504

I don't think it is a good idea to deprecate or remove features
we've supported for so long.

I've been pondering on this issue more while I away...

These warnings in scripting languages annoy USERS. In contrast
with compiled languages: only programmers see the warning when
they compile, most users never see warnings from gcc/clang.
This gives languages like C more freedom than us to deprecate
things (e.g. gets(3)).

Furthermore, with compiled languages, the old build will
continue working forever without annoying the user. I have
small C programs which haven't been rebuilt in a decade or
more, yet still run fine.

Scripting language users don't have that luxury and will
be affected by breakage when their distro upgrades Ruby for
them.

Not every user is a programmer and can fix every warning they
encounter. And often times, the programmer who originally wrote
the script has long moved on and a new user will choose
something written in a different language.

Looking back to a decade ago, I saw many people leave Ruby
because migrating to 1.8 to 1.9 was too painful and the language
was viewed as too volatile. Yet we still keep making the same
mistakes and lose users as a result :<

#17 [ruby-core:89063] Updated by Eregon (Benoit Daloze) 3 months ago

Just a quick opinion, deprecation is part of the migration part, better warn in a release in between than break functionality immediately.
We also warn for continuation FWIW.

I support removing flip-flops, it looks like a legacy strange behavior from Perl that doesn't belong to Ruby for me.
I think there is no need for such magic and confusing syntax to do something like this.

https://chrisseaton.com/truffleruby/flip-flops/ makes it clear there is little to no code using it, so I don't think it's an issue to deprecate and remove it.

#14183 is likely much more relevant for a discussion about compatibility ;)

#18 [ruby-core:89117] Updated by nobu (Nobuyoshi Nakada) 3 months ago

I agree with Eric.

It is too annoying to rewrite flip-flop.

A patch for flip-flop I found today is:

diff --git a/tool/enc-unicode.rb b/tool/enc-unicode.rb
index d953014952..c05d02358c 100755
--- a/tool/enc-unicode.rb
+++ b/tool/enc-unicode.rb
@@ -538,6 +538,7 @@
   IO.popen(%W[diff -DUSE_UNICODE_AGE_PROPERTIES #{fds[1].path} #{fds[0].path}], "r") {|age|
     IO.popen(%W[diff -DUSE_UNICODE_PROPERTIES #{fds[2].path} -], "r", in: age) {|f|
       ansi = false
+      in_hash = false
       f.each {|line|
         if /ANSI-C code produced by gperf/ =~ line
           ansi = true
@@ -545,7 +546,7 @@
         line.sub!(/\/\*ANSI\*\//, '1') if ansi
         line.gsub!(/\(int\)\((?:long|size_t)\)&\(\(struct uniname2ctype_pool_t \*\)0\)->uniname2ctype_pool_(str\d+),\s+/,
                    'uniname2ctype_offset(\1), ')
-        if (/^(uniname2ctype_hash) /=~line)..(/^\}/=~line)
+        if !in_hash ? (in_hash = /^(uniname2ctype_hash) /=~line) : (in_hash = /^\}/!~line; true)
           line.sub!(/^( *(?:register\s+)?(.*\S)\s+hval\s*=\s*)(?=len;)/, '\1(\2)')
         end
         puts line

Does this gain readability?

#19 [ruby-core:90411] Updated by jnchito (Junichi Ito) 5 days ago

Could you list this change on NEWS page?

This is because flip-flop is not used so often, but many people know it as one of Ruby's strange features. So this must be an important change.

Please refer my pull request: https://github.com/ruby/ruby/pull/2047

#20 [ruby-core:90413] Updated by shevegen (Robert A. Heiler) 5 days ago

I only got to know it after having read the news entry just now. :-)

I think the impact of its removal will be very, very little - not
many need it; and I am sure even less depend on it. Personally after
having seen it, I would not use it because it (to me) seems not
worth getting my brain to try to understand what it is doing. I
like to write extremely simple code that I can very quickly
understand.

I think the only question is whether matz is ok with the removal
(possibly if it was changed already), considering his statement about
avoiding backwards-incompatible change until 3.0 - but I think in this
case, it will really just about not affect anyone. I do not recall even
having seen flip flop used in real code in the last ~10 years or
so even including having checked quite a few gems by other people
on rubygems.org. Personally I think it is good to remove it - makes
ruby a tiny bit simpler to understand. :D
(Ternary + flip-flop is a bit to the mind like this language that
starts with Brain ...)

By the way, since 7 years ago at the least two wrote that they find
it useful - features are useful, but there are trade offs. I do
not find the flip-flop operator or way extremely useful for example.

Ruby took concepts and ideas from many other languages, including
perl, but ruby always was a LOT more readable than perl and perl
really did not care much at all about readability. So when you
compare ruby and perl, you also should compare the readability -
if you have a language that is "uglier", then a feature may be
less at odds with other parts of a language if the rest of the
language is already quite ugly to begin with (perl), whereas I
think syntax that is not "ideal", is more distracting in a language
that has a better syntax (ruby). Not sure if I managed to explain
that...

Also available in: Atom PDF