Changes in Ruby 1.9
Last major update on 2007-02-07.
I have scanned over 25000 lines of Changelogs to extract the changes between the stable branch and HEAD. These include important syntax additions, lots of modifications in the behavior of Procs and lambdas, new Enumerator and Enumerable goodies, convenient methods to interact with the OS, new IO stuff...
This is not Ruby 2.0!
Keep in mind that Ruby HEAD is being used to try wild and weird ideas. It should by no means be understood as a final say on what Ruby 2.0 will be like. A few decisions are firm and were labelled as Ruby2 in the Changelogs by matz. The below list also includes many crazy ideas (marked as EXPERIMENTAL in the Changelogs and here) which will probably be dropped in short.
Preliminary notes
- this is, by necessity, work in progress, as Ruby 1.9 keeps evolving; I‘ll try to keep it up-to-date.
- the snippets which include the resulting value in a comment were evaluated using my XMP filter, under ruby 1.9.0 unless otherwise stated. The 1.8 interpreter used were either ruby 1.8.4 or 1.8.5.
Table of contents
- Table of contents
- New syntax and semantics
- New constant lookup rules
- New literal hash syntax [Ruby2]
- Block local variables [EXPERIMENTAL]
- Block arguments are always local
- New syntax for lambdas [VERY EXPERIMENTAL]
- .() and calling Procs without #call/#[] [EXPERIMENTAL]
- Block arguments
- Method used for splat arguments: #to_splat
- Multiple splats allowed
- Mandatory arguments after optional arguments allowed
- c semantics
- Arguments to #[]
- printf-style formatted strings (%)
- Newlines allowed before ternary colon
- Module#instance_methods, #private_instance_methods, #public_instance_methods
- Module#const_defined?, #const_get and #method_defined?
- Module#class_variable_defined?
- #class_variable_{set,get}
- Module#attr is an alias of attr_reader
- Class of singleton classes
- Class variables
- #module_exec
- Extra subclassing check when binding UnboundMethods
New syntax and semantics
New constant lookup rules
Now constants are looked up in the following order:
- current class
- super classes except Object
- lexically enclosing classes/modules
- Object
The new rules entail differences in dynamic constant lookups too:
class ABAR = 1def foo(&b); instance_eval(&b) endenda = A.newa.foo { BAR } # => 1
vs. 1.8:
class ABAR = 1def foo(&b); instance_eval(&b) endenda = A.newa.foo { BAR } # =># ~> -:7: uninitialized constant BAR (NameError)# ~> from -:3:in `foo‘# ~> from -:7
See also ruby-talk:181646.
New literal hash syntax [Ruby2]
{a: "foo"} # => {:a=>"foo"}
Block local variables [EXPERIMENTAL]
Used as follows:
# {normal args; local variables}d = 2a = lambda{|;d| d = 1}a.call()d # => 2
When a variable is shadowed, ruby1.9 issues a warning:
-:2: warning: shadowing outer local variable - d
Block arguments are always local
a = 110.times{|a| } # !> shadowing outer local variable - aa # => 1
New syntax for lambdas [VERY EXPERIMENTAL]
a = ->(b,c){ b + c }a.call(1,2) # => 3
Note that this does not replace the traditional block syntax. Matz has already said the latter is here to stay, forever. The new syntax allows to specify default values for block arguments, since
{|a,b=1| ... }
is said to be impossible with Ruby‘s current LALR(1) parser, built with bison.
You can use the new syntax without parenthesis for the arguments:
-> { }.call # => nil-> a, b { a + b }.call(1,2) # => 3c = 1; -> a, b; c { c = a + b }.call(1,2); c # => 1
It can get very tricky though:
c = 2; -> ;c { c = 1 }.call; c # => 2
or even
c = 2; -> *d ; c { d }.call(1,2,3) # => [1, 2, 3]c = 2; -> ; c { c = 1 }.call; c # => 2
.() and calling Procs without #call/#[] [EXPERIMENTAL]
You can now do:
a = lambda{|*b| b}a.(1,2) # => [1, 2]
Note that you need the period:
a = lambda{|*b| b}a(1,2) # =># (eval):2: syntax error...# (a)(1,2)...
- ~> -:2: undefined method `a‘ for main:Object (NoMethodError)
You can use any expression inside the parentheses:
(lambda{|a,b| a + b}).(1,2) # => 3
.() will try to use #call no matter the receiver:
"foo".(1,2) # ~> undefined method `call‘ for "foo":String (NoMethodError)
Block arguments
Blocks can take &block arguments:
define_method(:foo){|&b| b.call(bar)}
Method used for splat arguments: #to_splat
- to_splat is used instead of #to_a.
nil.to_splat returns [].
Multiple splats allowed
As suggested by Audrey Tang, 1.9 allows multiple splat operators when calling a method:
def foo(*a)aendfoo(1, *[2,3], 4, *[5,6]) # => [1, 2, 3, 4, 5, 6]
Mandatory arguments after optional arguments allowed
def m(a, b=nil, *c, d)[a,b,c,d]endm(1,2) # => [1, nil, [], 2]
c semantics
a now returns a single character string instead of an integer:
a # => "a"
Arguments to #[]
You can use splats, "assocs" (hashes without braces) and block arguments with #[]:
RUBY_VERSION # => "1.9.0"RUBY_RELEASE_DATE # => "2006-06-11"class Foo; def [](*a, &block); block.call(a) end enda = (0..3).to_aFoo.new[*a, :op => :+]{|x| x } # => [0, 1, 2, 3, {:op=>:+}]
printf-style formatted strings (%)
%c can print a one character String (as returned e.g. by ?c).
Newlines allowed before ternary colon
p 1 == 2 ?0:1# >> 1
Kernel and Object
BasicObject
BasicObject is a top level BlankSlate class:
BasicObject.instance_methods# => ["__send__", "funcall", "__id__", "==", "send", "respond_to?", "equal?", "object_id"]Object.ancestors # => [Object, Kernel, BasicObject]
#instance_exec
Allows to evaluate a block with a given self, while passing arguments:
def magic(obj); def obj.foo(&block); instance_exec(self, a, b, &block) end endo = Struct.new(:a,:b).new(1,2)magic(o)o.foo{|myself,x,y| x + y } # => 3
send doesn‘t always call private methods anymore (#__send, #__send!, #funcall)
ruby-talk:153672 It is still possible to call them with the newly introduced #__send! and funcall methods.
class Foo; private; def foo; end; endFoo.new.funcall(:foo) # => nilFoo.new.send(:foo) # ~> in `BasicObject#send‘: private method `foo‘ called for #<Foo:0xa7d3267c> (NoMethodError)
Note that send(meth) (with no explicit receiver) can still call private methods:
class Klassdef hello(*args)"Hello " + args.join(‘ ‘)endendk = Klass.newk.send :hello, "gentle", "readers" #=> "Hello gentle readers"send(:puts, "foo") # prints "foo"1.send(:puts, "foo") # NoMethodError exception
- >> foo
- ~> -:10:in `BasicObject#send‘: private method `puts‘ called for 1:Fixnum (NoMethodError)
- ~> from -:10
Kernel#require
The value stored in $" when requiring a file contains the full path, i.e. it works like
$" << File.expand_path(loaded_file)
Object#=~
Now returns nil instead of false.
1 =~ 1 # => nil
Object#tap
Passes the object to the block and returns it (meant to be used for call chaining).
"F".tap{|x| x.upcase!}[0] # => "F"# Note that "F".upcase![0] would fail since upcase! would return nil in this# case.
Kernel#instance_variable_defined?
a = "foo"a.instance_variable_defined? :@a # => falsea.instance_variable_set(:@a, 1)a.instance_variable_defined? :@a # => true
Kernel#define_singleton_method
a = ""a.define_singleton_method(:foo){|x| x + 1}a.__send!(:foo, 2) # => 3
The new singleton method will be private:
a = ""a.define_singleton_method(:foo){|x| x + 1}a.foo(2) # ~> private method `foo‘ called for "":String (NoMethodError)
Kernel#singleton_methods, Kernel#methods
They now return an array of symbols (instead of strings):
a = ""class << a; def foo; end enda.singleton_methods # => [:foo]
Class and Module
Module#instance_methods, #private_instance_methods, #public_instance_methods
They now return an array of symbols (instead of strings):
class X; def foo; end endX.instance_methods(false) # => [:foo]
vs. (1.8.5)
class X; def foo; end endX.instance_methods(false) # => ["foo"]
Module#const_defined?, #const_get and #method_defined?
These methods now accept a flag specifying whether ancestors will be included in the chain, which defaults to true (see ruby-talk:175899):
module A; X = 1; def foo; end endmodule Binclude Aconst_defined? "X" # => truemethod_defined? :foo # => truemethod_defined? :foo, false # => falseconst_get "X" # => 1end
vs. (1.8)
module A; X = 1; def foo; end endmodule Binclude Aconst_defined? "X" # => falsemethod_defined? :foo # => trueconst_get "X" # => 1end
Module#class_variable_defined?
class X; endX.class_variable_defined? :@@a # => falseclass X; @@a = 1 endX.class_variable_defined? :@@a # => true
#class_variable_{set,get}
They are public in 1.9, private in 1.8:
class B; self end.class_variable_set(:@@a, "foo") # => "foo"
Module#attr is an alias of attr_reader
Use
attr :foo=
to create a read/write accessor. (RCR#331)
Class of singleton classes
singleton class inherits Class rather than its object‘s class
class X;end; x=X.new; class << x; self < X; end # => true
vs. (1.8)
class X;end; x=X.new; class << x; self < X; end # => nil
[ruby-dev:23690]