Showing posts with label rants. Show all posts
Showing posts with label rants. Show all posts

2008-09-01

{block}

Blocks. The most powerful out of the basic features of Ruby.

Block is a way to pass a bit of code into a function, to let the function execute it if it wants to, and as many times as it wants to. You know already some examples like
[1,2,5].each{|e| puts e}
, where the function
each
calls the block three times - once for each element of
self
.

Let's learn how to write a function that takes a block. I'd like to have a method of the class
Array
that converts the array to
Hash
, where the original array elements become keys, and the values are computed inside the block. Example of how it is supposed to work:
[1,5,3].keys_to_hash{|k| k**2}
#=> {1=>1,5=>25,3=>9}

["Ruby","Al2","O3","Cr"].keys_to_hash{|k| k.length}
#=> {"Al2"=>3,"O3"=>2,"Ruby"=>4,"Cr"=>2}
# remember that Hash does not maintain the order of elements
# so they might get reordered when written irb
So, our function definitely takes a block, and executes it once for each element, and collects the return values of the block as values in the hash. The code that does it is like this:
class Array
def keys_to_hash
raise LocalJumpError,"Block not given!" unless block_given?
h={}
each\
{ |e|
h[e]=yield(e)
}
h
end
end
First we raise an exception if the method was called without a block. This line is not obligatory, as the exception would be raised anyway at the moment when we try to execute the block, so I raise it here mostly to show you how to check if a block is given.

Then we create an empty hash, and then for each element of
self
(works like
self.each
) we write an element to the hash, using the current element
e
as the key, and
yield(e)
as the value. As you must have guessed by now, the keyword
yield
is a call to the passed block.

Finally we return the created
h
as the function result. You can check that the function works as expected.

Just one more example:
class Array
def each_consequent(n)
for i in (0..length-n)
yield(*self[i,n])
end
self
end
end

[2,3,5,7,11,13,17,19,23].each_consequent(3)\
{ |a,b,c|
puts "#{a} #{b} #{c}"
}

# output:
2 3 5
3 5 7
5 7 11
7 11 13
11 13 17
13 17 19
17 19 23
I'll explain just the most suspicious part here:
self[i,n]
is an array (subarray of
self
) and we call
yield
with
*
before the array to make the array splash into the three block arguments
|a,b,c|
. This splash operator is not always necessary, but it's nice to include it to make it clear that the arguments get splashed.

If block is an object...
There are in general two ways of passing a block to a next function. Let's define two functions that behave exactly like
each
:
class Array

def my_each1
each{|a| yield(a)}
end

def my_each2(&b)
each(&b)
end

end
The first one makes a trivial block itself - the block is created just to call the original block coming to
my_each1
with the argument. The second one uses the
&
operator to make the block be assigned into the variable
b
. Inside
my_each2
the variable
b
is a
Proc
object. You could call it by hand inside the function, using
b.call(arg)
or for short
b[arg]
, but in our example it is instead passed to
each
, and the operator
&
makes it sort-of-unsplash back into a block. Two other ways to do it (not very elegant, though):
p=Proc::new{|a| yield(a)}; each(&p)
, or another ugly way:
each{|a| b.call(a)}
. I give these example just to touch your brain and make you understand!

If the block is not passed into a function declared with a block parameter, like
my_each2
, the value of
b
is
nil
, and you don't have to call
block_given?
to check it.

...then we can store it
Now another useful trick. If we can receive a block as an object, or wrap it into a new
Proc
, then it's an object, and can be stored in a variable. Look:
class K

def store_block(&b)
@b=b
end

def call_block(*args)
@b.call(*args)
end

end

k=K::new
k.store_block{|a,b| puts "#{a}::#{b}"} # no output to the console
k.call_block("Al2O3","Cr") # output: Al2O3::Cr
k.call_block("Hi","there") # output: Hi::there
So, we saved the passed block, and called it later. Note one very useful trick: if we receive the arguments as
*args
and pass them on as
*args
as well, then any set of arguments, no matter how many of them you pass to
call_block
, will get forwarded to the block call. (Of course now calling
k.call_block(1,2,3)
will print just
"1::2"
because our block takes two arguments, which means it ignores the third one; but the argument gets lost in the block, and not in
call_block
).

This block saving is not useless. You can for example call a method that saves a block, and executes it later as a callback to an event that happens inside the object. This is a very useful behaviour.

Passing more blocks
Unfortunatelly, Ruby doesn't support passing more blocks to a function. You can have only one parameter with
&
, and there is only one
yield
too. But Ruby does allow passing multiple regular arguments, so what's the problem? Let's write a function that sort of takes two blocks, and calls one of them with the result returned by the call to the other with the argument 5, or opposite:
def random_caller(b1,b2)
raise ArgumentError,"Arguments must be Procs"\
unless b1.is_a? Proc and b2.is_a? Proc
if rand(2).zero?
b1.call(b2.call(5))
else
b2.call(b1.call(5))
end
end

q=lambda\
{
random_caller(lambda{|x| x+2},lambda{|x| x**2})
}
q[] #=> 27
q[] #=> 27
q[] #=> 49
q[] #=> 27
q[] #=> 27
First we check if what we really got are procs. Then we randomly call one of them with
5
and the other with the result of the first one, or the opposite, and return the result.

Now the call. The structure
lambda{|arg| exp}
is more or less the same as
Proc::new{|arg| exp}
and
proc{|arg| exp}
. So
random_caller(lambda{|x| x+2},lambda{|x| x**2})
is a call to our function, and we can expect the result of the call to be either
(5+2)**2
which is
49
, or
(5**2)+2
which is
27
.

Now we must call our function multiple times. We could do it like this:
5.times{random_caller(lambda{|x| x+2},lambda{|x| x**2})}
But, as a part of this tutorial, I made the call to the function into another proc, and stored it in
q
. As you see, you don't even have to pass a block to a function to store it somewhere. You can create a proc just like that, and store it in a local variable, and then call it using
q[]
or
q.call
.

Scope
The scope visible to a block is its declaration scope. What is very interesting, even when the scope is no longer accessible, because the control left the function, it still exists if a lambda was declared there and can use it. This example illustrates the complicated words I just said:
def create_blocks
x=nil
getter=lambda{x}
setter=lambda{|v| x=v}
[setter,getter]
end

s,g=*create_blocks
s[6] # or s.call(6)
g #=> 6
s[:R]
g #=> :R
The scope from inside
create_blocks
is not lost, even though the control left the method and will never return. The variable
x
is still accessible by the lambdas declared in the scope.

Other sources
Here are some link to learn more about gotchas in Ruby's blocks.
Ruby blocks gotchas
Proc vs lambda
Wikipedia - Closure (in many other languages the Ruby clock thing is called closure, or probably more like the closures are called blocks in Ruby)
Wikipedia Smalltalk (this blocks are pretty modern and fresh programming things, aren't they? well, they're not; have a look at Smalltalk (1980))

2008-08-28

include Module

Hello. Today about including a module, and about modules in general.

One potential use of a module, as a namespace for a set of functions, you have seen here: Fibonacci numbers - lazy evaluation. Now it's time to show the main use of modules, the one for which they are introduced in Ruby: mixins.

Mixins
Or, more descriptive: (mix-in)s, things that you mix-in. Let's skip the theory for now and go to an example.

Let's say we have a class whose objects we want to make comparable. Let it be
class Person
, and let
p1<p2
if person
p1
is younger than person
p2
. The traditional approach here is like this:
class Person

def initialize(name,age)
# skip validation for simplicity
@name=name
@age=age
end

attr_reader :name,:age

def <(p2)
@age<p2.age
end

end
OK, now we can compare two people like:
t=Person::new("Tom",23.3)
z=Person::new("Zuz",23.2)
t<z #=> false # as expected
But if we try
t>z
or
t==z
or
t>=z
..., it will be a
NoMethodError
, because only the method
<
has been defined. Of course we can define all the 6 comparison methods, but that wouldn't make today's post, would it? Let's do it using a module
Comparable
, already existing in Ruby, and the operator
<=>
.

<=>
The method
<=>
works just like
comapreTo
in Java - it takes an argument and compares
self
with the argument, yielding
-1
,
0
or
1
if
self
is less than, equal, or greater than the argument, respectively. This strange-looking operator is defined for all built-in comparable types in Ruby, try
5<=>7
for instance. Let's define it, bearing in mind that it is already defined for standard types!
class Person
def <=>(p2)
@age<=>p2.age
end
end
That was trivial. Now we could define all the operator like this:
class Person
def <(p2);(self<=>p2)<0;end
def >(p2);(self<=>p2)>0;end
def ==(p2);(self<=>p2)==0;end
def >=(p2);(self<=>p2)>=0;end
def <=(p2);(self<=>p2)<=0;end
end
Remember one thing: In Ruby, if something looks inefficient, it probably is. So, the above code looks inefficient. First, because it has very low entropy, meaning it repeats the same thing over and over again, and second, because if we define another class which we also want to be comparable, we'll have to copy the 5 lines without any difference duplicating the code and lowering the entropy even more.

One more word - we don't define
!=
because it is automagically defined as the opposite to
==
and even cannot be redefined.

module
Let's do it like it should be done! Let's define the five comparison methods in a module, and let's mix the module into our class like this:
module Comparable
def <(p2);(self<=>p2)<0;end
def >(p2);(self<=>p2)>0;end
def ==(p2);(self<=>p2)==0;end
def >=(p2);(self<=>p2)>=0;end
def <=(p2);(self<=>p2)<=0;end
end

class Person
include Comparable
end

class OtherComparableClass
include Comparable
end
Isn't that better? Now it's going to turn out even more better when I tell you the module
Comparable
is already defined in Ruby, with the five functions just like we defined them here, so when you want to make a class comparable, you just
include Comparable
and
def <=>(other)
, and all works! The module has also a bonus:
between?(min,max)
, working like expected (both ends inclusive).

Now note one thing: the module uses the method
<=>
even though it is not define in it, nor in its ancestors, nor anywhere. But module is a trusty animal: it trusts you that you won't include it unless you define all the missing methods it uses!

The biggest thing in the world
Let's play for a moment with
Comparable
. Let's define an object that claims to be the biggest object in the world.
biggest=Object::new

class << biggest
include Comparable
def <=>(other)
other.equal?(self) ? 0 : 1
end
end

biggest>5 #=> true
biggest<=1000000 #=> false
biggest>["X"] #=> true
biggest>biggest #=> false
What we did: we defined the object, then we sort of declared sort of class that our
biggest
is sort of instance (in fact it's the object's eigenclass, but let's leave it for another post). Just understand that declaring the methods like we do it here is exactly like declaring them in the object's regular class, only they are accessible only for our
bigger
, and not for all the ``Object`` instances. It's defining methods just for one object (as there is only one biggest object, of course!).

The
other.equal?(self) ? 0 : 1
part might need an explanation. If we just returned
1
, then the object would be greater than all objects including itself, so
biggest>biggest
would yield
true
, and
biggest<biggest
would return
false
. We want the object to know that it is as big as it is, so when the object is compared with itself, we want it to know they are equal. That's why we compare it with itself. Now, why we use
equal?
and not
==
? Well, the method
==
defined inside
Comparable
calls
<=>
which in turn calls
==
and so on until
SystemStackError
. But the function
equal?
works in another way: it checks if the two object are the same
instances
:
a="abc"
a=="abc" #=> true
a.equal?("abc") #=> false # other instance of String
a.equal?(a) #=> true
a.equal?(a.dup) #=> false
So that's the method we're looking for - it will return
true
only if we compare
biggest
with
biggest
itself.

One word of a summary: if you define a method within a class, you have to instantiate the class to make the method really accessible to the world. But if you define a method within a module, you first have to include the module in a class, and then to instantiate the class, to be able to call the method.

Kernel and puts
What's this
Kernel
? It's a module that is included in the class
Object
, and thus in all the classes you ever define, as they all are descendants of the class
Object
. Now there comes the explanation how come you can write
puts
and it works.

If you open irb, or take an empty .rb file, you are inside a class. Check it:
irb(main):099:0> self
=> main
irb(main):100:0> self.class
=> Object
So, were inside some
Object
instance. So what happens if we write
puts
? We call our object's private method
puts
. We can call it even though it is private because we are inside the object (but if you try
self.puts
you'll see it is private; by the way, it is not like in Java here -
self
is just as any other object so you cannot call private methods on
self
, you can only do it without prefixing them with
self
). But the truth is that the method is not defined in the object - it is defined inside the
Kernel
module (as a private function), and in this way it got to our
main
object. And to any other object, too:
class K
def kk
puts "in K"
end
end
Now, the call to
puts
that you do when writing
k=K::new; k.kk
is a call to
k
's private method
puts
, which is there also because of mixing in
Kernel
into the class
K
(into the
K
's ancestor:
Object
, precisely speaking). So, if we had a class
StupidClass
, and we were tired of all the noise this class' instances do by
:puts
ing stupid things, we can mute all class' instances:
class StupidClass
def puts(*args)
# ignore
end
end
Other classes, including our
main
, will still be able to
puts
messages.

But if we don't want to mute the messages completely, but just to make them less noisy, we can do this:
class StupidClass
def puts(*args)
Kernel.puts(*args.map{|a| a.to_s.downcase})
end
end

stupid_object.puts "AbC",5,:XX
# Output:
abc
xx
Of course we have to call the
Kernel
's static method
puts
and not just write
puts
, because it would make a self-reference. Also note that the static method
Kernel.puts
is not the one that is included in the class
Object
.
Kernel
has two
puts
methods:
irb(main):009:0> Kernel.private_instance_methods.grep /puts/
=> ["puts"] # instance method, called by Object::new.puts
irb(main):010:0> Kernel.singleton_methods.grep /puts/
=> ["puts"] # static method, called by Kernel.puts
The two methods are independent - none of them calls the other.

2008-08-15

rescue

About exceptions today. First - if you're new to exceptions, probably 'exception' means to you 'an ugly error message, full of Access denied, memory under 0x462F3ED4 cannot be read stuff, contact the sucker who sold you this product.' Time to change this way of thinking!

Why the hell they invented exceptions
Imagine a complex system, let's say, a system to operate some machine in a factory. The system is divided into layers, that is (for example, in order) direct motor control, motor control proxy, motor controller, control logic, user commands layer, several other layers, the machine operation layer, several more layers, and finally the user interface, where user wants the machine to do something.

So you can imagine, that when user presses a button, then a function from user interface layer calls a function from the next layer, that calls a function from the machine operation logic layer, that... that finally sends a signal to the inverter to run the motor. And now imagine that the motor is completely broken, burnt, stalled or stolen. It's a critical error, so user must be immediately informed about this, and no further action of any of the layers is needed.

The naïve solution: each of the functions should return an integer with error code, and each function, when calling the next one in the chain, should check its return value, and if it signalises an error, it should return immediately with the same error code, until the last function (the first that was called) gets the message. It's a good solution, meaning that it can work. But it's a very bad solution:
- The code becomes ugly and long.
- Functions cannot return any other value because they already return the error code, and it complicates even further.
- If a function has to do something no matter if it succeeded or not (like close a file or release resources), and it complicates even further than further.
- The code becomes ugly and long.
- The code becomes ugly and long.
Have a look at an example:
def prepare()
if motor_in_bad_mood?
return 225 # the error code for the problem
end
inverter.init()
return 0
end

def do_it()
if ufo_stole_the_cables?
return 843 # the error code
end
inverter.operate()
# further operation
return 0
end

def almost_do_it()
f=allocate_resources()
if (ret=prepare())!=0
f.free_resources()
return ret
end
if (ret=do_it())!=0
f.free_resources()
return ret
end
f.free_resources()
return 0
end

def user_says_do_it()
if (ret=almost_do_it())!=0
puts "The operation returned the error code! (#{ret})"
end
end
If you're not completely blind, you see the ugliness of this code. (Of course in Ruby we could do some improvements, but imagine it is C. And remember there is a lot more functions that call each the next one.)

Any idea for a solution? Well, the best one is, if the most inner function could inform the most outer function that something's completely wrong. But how to do it? And what if we don't want to inform the most outer function, for example because the problem is not so critical, and can be resolved by the program?

Let's finally present the solution with exceptions, or
Exceptions
, as we should call them now.
class CriticalMotorError < RuntimeError
end

def prepare()
if motor_in_bad_mood?
raise CriticalMotorError,225
end
inverter.init()
end

def do_it()
if ufo_stole_the_cables?
raise CriticalMotorError,843
end
inverter.operate()
# further operation
end

def almost_do_it()
f=allocate_resources()
begin
prepare()
do_it()
ensure
f.free_resources()
end
end

def user_says_do_it()
begin
almost_do_it()
rescue CriticalMotorError => e
puts "The operation returned the error code! (#{e.message})"
rescue RuntimeException => e
puts "Something even worse happened: #{e.message}."
end
end
Notice any differences? Let's explain what happened. First, we declared our error class, descendant of the standard error class in Ruby,
RuntimeError
(which is a descendant of
Exception
used for most error that happen during program runtime). Our exception class doesn't do anything special, it just inherits from the ancestors.

Now, when an error occurs, we
raise
an exception (in other languages the keyword throw is often used here). That means that we create a new instance of our exception, pass it an argument (exception simply stores it as an error message and does nothing with it), and then
raise
thus created exception. Raising means that all further actions in the current function are aborted, and the control returns to the higher function, but here also all actions are aborted, and the function exits immediately, and all functions in the chain exit in a row. If we just threw an exception and then didn't take care of it, it would exit all the functions, and finally also exit the program with an error message (try to type this in irb:
def x;0/0;end;def y;x;end;def z;y;end;z
to see this behaviour in action).

But here we don't want the program to exit. So we make a trap. A trap is the
begin
and
end
in
user_says_do_it
, and the
rescue
. Basically, if things that are called after
begin
throw an exception, and the exception is mentioned in one of the
rescue
clauses, then the rest of the block after
begin
is skipped and the control goes to the right
rescue
clause (the first that mentions the actual class of the exception), and then resumes after
end
, and continues to run the program normally (the exception is cancelled once the control enters the
rescue
clause, and the exit-immediately madness stops).

What we do in the
rescue
clause, we print an error message, including the message (error code) that we read from within the object
e
which is our exception. Simple, elegant, painless.

As you see, there's one more trap, inside
almost_do_it
. It also detects exceptions raised from the block, but it doesn't rescue them, it just isn't interested in what really happened, or it decides it doesn't have power to serve any errors correctly, so it just lets the exceptions pass through, also skipping the rest of the block (so if the exception was raised by
prepare
,
do_it
won't even try to execute. But here's the trick: the
ensure
block gets executed no matter what happened inside the
begin
block. It executes both when the block completes normally, and when it is interrupted by an exception, but
ensure
doesn't cancel the exception, it just stops for a moment to do what it has to do, and goes on with the unrolling madness.

As you see, the exceptions are very useful, simple, elegant, powerful and in general good. Use them!! Learn them, use them, think about them, or else you're not a programmer for me.

Final remarks about exceptions
The two following examples are equivalent:
begin
try_something()
puts "Success." # of course this line is executed only if no exception was raised
rescue SomeError => e
error()
# possibly more rescue clauses
end
And the second, looks a bit nicer for me:
begin
try_something()
rescue SomeError => e
error()
# possibly more rescue clauses
else
puts "Success."
end

Another remark.
begin
# ...
rescue RuntimeError
# ...
rescue CriticalMotorError
# ...
end
This is useless, because our
CriticalMotorError
is also a
RuntimeError
, so the first
rescue
will be triggered, and always when a
rescue
is triggered, all following
rescue
s are skipped and not even checked.

Also, as you see, the
=> exception_var
can be omitted. The exception class name can be omitted also, and it defaults to
StandardError
. For standard exception classes, check QuickRef, the part Exceptions, Catch, and Throw (
catch
and
throw
are not so good tools, though).

The last remark. If a function in the calling chain thinks it cannot serve the exception, but thinks that it could add some additional info to the error, it can
rescue
it and either throw a new error with some more data (possibly of some other class than the original exception), or it can do something like this:
begin
# ...
rescue SomeException => e
puts "The exception was rescued: #{e.message}"
puts some_additional_info
raise e
end
In this way, the exception gets partially served, and then reraised so that it does not get cancelled at this point.

Use it, use it, use it!

2008-08-12

class Class

Today, let's have a look at classes in Ruby. You can get basic information about these animals under the links on the right, here I'm going to clarify some more unclear areas, like:
- Constructors,
- Static methods,
- Methods overloading,
- Fields.

Constructors
How to make a new object of a class? Well, in most old-school languages there are constructors. They are some sort of a hybrid methods: they are called as if they were static methods, but inside them, it was just like inside a normal methods - you can access object fields and call other its methods. In Ruby the two parts - static and nonstatic - are separated. In fact, you make a new object of class Klass, like this:
Klass::new
or this:
Klass.new
. It doesn't resemble classic constructor calling which would be more like
new Klass
. In fact, what you do in Ruby, you call a static method
new
. This method is the method of each class as it is the method of the class
Class
. And this
Class::new
does some magic: it creates a new object, allocates memory for it, makes it be this or that class, and in general performs some action that is not possible anywhere else in Ruby, only in
Class::new
.

Once the object is constructed, the magical method wants to initialise the object, so that it can get some specific attributes (until now, this object's only attribute is its class). To do this, it calls object's method
initialize
, which is a perfectly regular instance method - not static, not even a bit. So that explains why you declare the method
initialize
and then call
new
to create the object. The arguments you pass to
new
are completely ignored inside
Class::new
, they are only sort of forwarded to object's initialiser. (Later you'll learn how to do such a forwarding.)

A small example to test what I just said:
class K
def initialize(a,b,c)
puts "a=%d and b=%s and c=%02X"%[a,b,c]
end
end

K::new(131,"quale",63)

Static methods
Prepare for a shock now: there are no static methods in Ruby. Yes, you read correctly. What I was calling a static method (and I'm going to use this naming convention normally because it makes things easier) is in fact an instance method of the class object. Because you must know that all classes, like
String
or
Array
or anything, are in fact objects (instances) of the class
Class
. You can check it:
5.class #=> Fixnum
"abc".class #=> String
Array.class #=> Class
So, for instance, Array is an object of the class Class. So when we write
Integer.induced_from(8.3)
, it might look like a static method of the class
Integer
, but it is not quite it. That's why you cannot say
10.induced_from(8.3)
, even though
10.is_a? Integer
, so you could call a static method in this way in languages like C++ or Java. (
10.is_a? Integer
this is how you check if an object is an instance of the given class;
10.class==Integer
wouldn't work because
10.class
is in fact
Fixnum
and
Fixnum
is an ancestor of
Integer
).

But OK, if it's getting too hard for you, just remember that what seems to be static methods, is not quite the same as static methods in other languages. But it is similar.

Just a code sample
class K
def self.static_method1
puts "in static 1"
end
class << self
def static_method2
puts "in static 2"
end
end
end

def K.static_method3
puts "in static 3"
end

K.static_method1
K.static_method2
K.static_method3
One day I'll explain why methods can be declared in so many ways. For now just remember that they are all alike.

Methods overloading
Today's a negative day: there's no method overloading in Ruby. If you define a method, and then define another method with the same name, the last one is the one that will really be accessible. There's no way to call the first one. Try it yourself, change a method in one of the standard classes:
class String
def length(q)
puts q
end
end

"OneTwoThree".length(456)
As you see, the newly created method
length
was called. There is no way to call the old one:
"aString".length
yields an error now.

So how can you create a method that can receive either String or Array or possibly Integer? Well, Ruby is a dynamically typed language so of course if you just define the method, it can receive arguments of any type. But if you want to serve them differently, then you must use a condition and check the class of the passed object:
def test_class(arg)
if arg.is_a? String
puts "Called with String."
elsif arg.is_a? Array
puts "Called with Array."
elsif arg.is_a? Integer
puts "Called with Integer."
else
puts "Called with something else."
end
end
So that's how you can emulate overloading. But the truth is that we can simplify a lot the last example:
def test_class(arg)
puts "Called with %s."%arg.class
end
Of course the behaviour is different (e.g. you'll get
Fixnum
instead of Integer for numbers), but that's more ruby'ish, and the function looks nicer, too.

Another trick to emulate method overloading is default parameters, like here:
def def_par(a,b=6,c=a+b)
puts c
end

def_par(3) #=> 9
def_par(3,9) #=> 12
def_par(3,9,2) #=> 2
As you see, the default values can be variable, and even very variable as
c
here.

One more trick about overloading: let's say we want to receive a list (Array) of Strings into our method, and print them, like here:
def str(list)
list.each{|s| puts s}
end
But this has a little inconvenience - if you happen to pass just one String to the method, you must write
str(["string"])
. So we'd like to be able to pass one String, or Array of Strings. We could of course check the class of the argument but let's move on and learn something else:
def str(list)
Array(list).each{|s| puts s}
end
The method
Array
(it's a method here, not a class) returns an array containing one element - the argument, or returns just the argument if the argument is already an Array. So that's exactly what we needed.

Last one example, without a deep explanation for now:
def str(*list)
list.each{|s| puts s}
end

str("one")
str("one","two","three")
str(*["one","two","three"])

Fields
It is not elegant to declare public fields in classes. In Ruby it is also not possible. Fields in classes look like this:
@field
. They can be accessed only from within the object, they cannot even be accessed from inside other object of the same class (what distinguishes Ruby from C++ or Java). So how to make them visible? You define setter and getter. You can do it like this:
class K

def initialize(a)
@a=a
end

# this is the getter
def a
@a
end

# this is the setter, isn't that the most elegant syntax for a setter?
def a=(v)
@a=v
end

end

k=K::new(56)
puts k.a #=> 56
k.a="33"
puts k.a #=> "33"
Of course you can write some more interesting code, like value validation and so on, especially in the setter. But if this trivial setter/getter is what you need, you can use an abbreviation:
class K

#...

attr_accessor :a,:b # trivial setter and getter for @a and @b
attr_reader :c # trivial getter and no setter for @c
attr_writer :d # just the setter (well, I never used this)

end
Don't look at these colons in this way, they won't bite. We'll get to Symbols later, for now just remember how to define the attribute accessors in trivial and in nontrivial way.

One last remark about fields: they are always defined. If you run a new irb console and write
xx
, it's going to say that the variable or method is not defined. But if you do this:
class KK
def test_xx
puts @xx
end
end

KK::new.test_xx
you'll just see
nil
. Class attributes (that's the more ruby-like name for fields) are never undefined. They are just
nil
.

All for today, thanks for listening.