Links
Tags
apache
armenia
books
bsd
c
c++
chips
cinema
concurrency
cooking
database
dragonfly
erlang
filesystem
freebsd
fun
hardware
java
javascript
json
languages
linux
lyric
mac_osx
mail
math
misc
music
personal
poems
presentation
programming
python
references
ruby
rubyjs
scm
software
spiking_neural_net
study
sysadm
sysarch
technology
testing
travel
virtualization
web
wee
windows
Rite will be a complete rewRite of the Ruby interpreter, whereas Ruby2 will be the new revision of the Ruby language.
Rite:
- bytecode
- generational GC
- native threads
- new regular expression engine (Onigurama)
- m17n (multilinguization)
Ruby2:
- real keyword arguments (not just hashes)
- new block variable scope
- pre/post/wrap methods
- selector namespaces (?)
- a few other modifications that clean up the language (but no dramatic changes, Ruby will stay the same)
This is mainly a repetition of Matz’s ideas presented at RubyConf 2003 "How Ruby Sucks" (did Guido van Rossum ever told you How Python Sucks? :-). More information on this subject is given in Rite or RiteSuggestions.
end summary::
New Local Variable Scope
Block parameters are block-local, whereas all other variable assignments inside the block do no longer create block-local variables.
But what about block-local variables other than the parameters?
Solution 1
By using more block-parameters than actually used for the arguments. For example:
ary.each do |i, aLocal, anotherLocal|
...
end
This seems odd to me, as it’s no longer clear how each behaves, which variables are actually parameters, and which are not.
Solution 2
Introduce new syntax for block-local variables. For example:
ary.each do |i| <aLocal, anotherLocal>
...
end
Or more verbose:
ary.each do |i|
local aLocal, anotherLocal
...
end
A local * or <*> would then mean, that all used variables are local to the block.
Keyword arguments
Old hash syntax for method calls
Will the following become obsolete?
def foo(hash)
...
end
foo("port" => 8080, "url" => "...")
Instead (Rite):
def foo(**hash)
...
end
Or explicitly (Rite):
def foo(port: nil, url: nil)
...
end
foo(port: 8080, url: "...")
I would argue for making it obsolete, i.e. removing it, for the sake of clearness.
No parentheses?
Will it still be possible to ommit parentheses? Will the following work?
foo port: 8080, url: "..."
I don’t like this when used in combination with keyword arguments, as it reminds me of Smalltalk, but is completely different (first part is a method instead of a receiver/object in ST).
Passing Arguments Through
Will this work?
def wrap_a(*args, **keys, &block)
a(*args, **keys, &block)
end
Of course, it should!
Complex argument lists
Will this be possible?
def foo(a, x=5, *args, b: 42, c: nil, **keys, &block)
...
end
foo(1)
# => a=1, x=5, args=[], b=42, c=nil, keys={}, block=nil
foo(1, 2, 3, 4, c: 5, port: 8080) {...}
# => a=1, x=2, args=[3,4], b=42, c=5, keys={port: 8080}, block={...}
I really don’t want to write a parser for this ;-)
Don’t care argument list
As argument lists become more complicated, wouldn’t it be nice to have a syntax for don’t care? This is especially useful for pre and post methods:
def foo(a, *args, b: 42, c: nil, **keys, &block)
...
end
def foo:pre(...)
# don't care about the arguments
end
Don’t need to write:
def foo:pre(*a, **b, &p)
...
end
Maybe … isn’t appropriate, as it reminds me of ellipses in C++. Probably no big win in clearness, as usually pre and post methods are used for meta-programming and not by the programmer itself.
Another possible solution is to not perform arity checks for pre or post methods, so that argument lists can be ommited, when not needed:
def foo(a, b, c)
...
end
def foo:pre
puts "pre"
end
But that would make them a bit more special than normal methods are, which is IMHO not a good choice.
Pre/Post/Wrap Methods
Great improvement for meta-programming like Aspect Oriented Programming (AOP).
Recursive Make Considered Harmful Peter Miller (auf Deutsch)
Go To Statement Considered Harmful Edsger W. Dijkstra
Sorry, but the article is in German.
www.linuxenterprise.de/itr/online_artikel/psecom,id,407,nodeid,9.html
Imagine you have written a method that works on arrays, using the [] method to access specific elements. Let’s call this method process:
def process(anArray)
...
anArray[i] # access i'th element
...
end
At the beginning there’s no problem with using this method on arrays, as your arrays are small:
arr = Array.new
for i in 1..1000
arr[i] = i**2
end
process(arr)
After some time, your array grows, but not the number of elements in it, say only a few elements in your array are defined, but with indices in the range from 1 to 1 billion.
arr = Array.new
arr[23] = 66.5
arr[25_333] = 4
arr[1_000_000_000] = 8
process(arr)
You’ll probably not have enough memory to try out this example, as arrays in Ruby will automatically grow to their largest index. In the example above, we would need around 4 GB of memory, for only three elements.
Clearly, what you need is a sparse array. In Ruby, that’s simply a Hash:
arr = Hash.new
arr[23] = 66.5
arr[25_333] = 4
arr[1_000_000_000] = 8
process(arr)
Notice how nothing except the first line has changed.
Defining a default value for undefined elements in the hash is simple again:
arr = Hash.new(default_value)
...
...
This would return default_value for non existing indices/keys.
Imagine you now want to call the process method with an array that contains all numbers from 1 to 1 billion in reversed order. Neither arrays nor sparse arrays will help here, due to their high memory consumption. What we need are functions, or in Ruby, Proc objects.
arr = Proc.new {|i| 1_000_000_000 - i}
process(arr)
The function (or Proc object) in the above example can be seen as virtual array. We can get the value of the i’th element in the same way we would have done with an array:
arr[i]
which of course in the case of a Proc object is equivalent to:
arr.call(i)
This nice consistency is what I was talking about at the beginning of the article. Did you get it :-)
The presentation slides can be found here:
But, which graphics library should I use?
I am not looking for a graphics library that rules the world. All I want is to draw directly into the frame-buffer. In the good ol’ DOS days, it was so simple. Two assembler commands to switch into mode 13h (320x200x8):
mov ax, 13h
int 10h
Then I was able to write directly into the frame-buffer (I believe the memory location was 0xa000).
I started with evaluating libGGI, as it’s very portable. But after I was ready with the program, I realized that the pixel routine was too slow. So I tried Clanlib, but it failed to compile on FreeBSD. I though, ok, let’s try libSDL. I read some docs about SDL, but the pixel routine in the tutorial tried to handle all possible color depths. Then I tried Allegro. I used it in the past (yeah, good ol’ DOS days), and found it very pragmatic, not trying to abstract every piece of my hardware.
Allegro
Wow, I hacked up my first little program in 5 minutes. It really looks like programming in DOS. Everything is so simple.
if (allegro_init() != 0)
{
// fail
}
install_keyboard();
set_color_depth(32);
if (set_gfx_mode(GFX_AUTODETECT, 800, 600, 0, 0) != 0)
{
// fail
}
acquire_screen();
// ... draw on screen
release_screen();
readkey();
It is easy to create a bitmap (for double buffering), write directly into it, and copy it to screen:
BITMAP *bmp = create_bitmap(800, 600);
for (int row=0; row<600; row++) {
for (int col=0; col<800; col++) {
((unsigned int*)bmp->line[row])[col] = makecol(255,0,0); // fill red
}
}
blit(bmp, screen, 0, 0, 0, 0, 800, 600);
And peng, it’s displayed on the screen, without delay! That’s all I need for my fractal zoomer. Great!