Some more things I love about Ruby

February 26, 2006

First of all, I love %w{ }. It is wonderful. When prototyping it makes me save lot of digits. I know it’s a bit perlish (exspecially because you can also %w[ ] or %w/ /), but it is a great feature.

The %x{ } for commands (and ``). Yeah, perlish. But I needed it in some system automation scripts in Python. I know I could use subprocess… but sometimes I need something more stupid. I wrote a class for this (and you can find it in my blog).

Regexps… I’m a python fan… but I have to admit perl’s syntax makes a lot of sense (and it is the one I have in sed or vim too, at least to some degree). Quite like that syntax in a cleaner environment.

Having the % operator on strings is good. It resembles me Python. I suppose it’s a bit less powerful (I think it works only with lists, but since you can use #{} in ruby strings, the need for dictionaries is small). Moreover some of the most un-pythonic code I wrote is due to “creating” dictionaries. If you don’t take care, you may find yourself with troubles. Of course even the #{} can be abused and so be source of problems.

<< on strings and arrays. I quite liked streams in C++. Yeah, not the same thing, but…

I’ll write more later… (there are also things I don’t like, but I should study more to fully understand them).

Advertisements

Ruby arrays and matrices

February 22, 2006

One of the first things you learn when reading a book on Ruby is that “variables” hold references to objects. Consider


a = Foo.new
b = a

Both a and b contain the same instance of the object. Fine. Simple. Java does the same and so does Python. You just know what that means and you know that if you want a copy instead (that is to say b and a should change indipendently) you must dup or clone them.


a = Foo.new
b = a.dup

Now it comes to arrays. Ruby arrays are much like Python list. They are powerful objects. And have something Python lists do not have, some more constructor. From the ruby doc:

Array::new
Array.new(size=0, obj=nil)
Array.new(array)
Array.new(size) {|index| block }

Returns a new array. In the first form, the new array is empty. In the second it is created with size copies of obj (that is, size references to the same obj). The third form creates a copy of the array passed as a parameter (the array is generated by calling to_ary on the parameter). In the last form, an array of the given size is created. Each element in this array is calculated by passing the element’s index to the given block and storing the return value.

We analyze the very first constructor. It makes perfectly sense: consider this:

  l = Array.new(5, "") # ["", "", "", "", ""]
  l[1] ="foo"
  l # ["", "foo", "", "", ""]

Now consider this:

    l = Array.new(5, []) # [[], [], [], [], []]
    els = %w{ el1 el2 el3 el4 el5 }
    l.each_index { | index | l[index].push els[index] }
    #  [
    #    ["el1", "el2", "el3", "el4", "el5"], 
    #    ["el1", "el2", "el3", "el4", "el5"], 
    #    ["el1", "el2", "el3", "el4", "el5"], 
    #    ["el1", "el2", "el3", "el4", "el5"], 
    #    ["el1", "el2", "el3", "el4", "el5"]
    #  ]

This is the correct result. But this probably is not what we wanted to obtain. The “correct way to initialize l” would have been

    l = Array.new(5) { | dummy | Array.new } # [[], [], [], [], []]
    els = %w{ el1 el2 el3 el4 el5 }
    l.each_index {| index | l[index].push els[index] }
    # [["el1"], ["el2"], ["el3"], ["el4"], ["el5"]]

This time for each line we are creating a “new” empty list, not the very same one.

In this case you probably should have been using the Matrix class, anyway.


get_sublist in prolog

February 20, 2006

The hardest thing when programming prolog, is to change your mind. In fact declarative programming (while powerful) is hard to get in touch. I always tend to think imperatively, even if I attended formal logic lessons in the University.

Now just a couple of easy things… I’m a beginner.

get_sublist(Start, Len, List, Sub) :- append(L1, L2, List),
length(L1, Start), append(Sub, _, L2), length(Sub, Len).

This way you get a sublist. The style is declarative. The efficience is …. well we ll’see later.
An “imperative” version is

get_sublist(_, 0, _, []).
get_sublist(Start, Len, List, [H | Acc]) :- nth0(Start, List, H),
succ(Start, NStart), succ(NLen, Len),
get_sublist(NStart, NLen, List, Acc).

It’s not as clean, but should be more efficient. It uses an accumulator variable. In fact this algorithm is not really declarative. We could say that it does the same thing than

def get_sublist(start, len, list, acc)
if len > 0
acc.push list[start]
nstart = start + 1
nlen = len - 1
get_sublist(nstart, nlen, list, acc)
end
end

Incidentally this is ruby code, you can test it with

l = []
get_sublist(2, 3, %w{ a b c d e f g}, l)
l.each { |e| puts e}

And now… lets see if we optimized or not. This is comes from SWIProlog.

5 ?- time(get_sublist(2, 3, [a, b, c, d, e, f], Acc)).
% 22 inferences, 0.00 CPU in 0.00 seconds (0% CPU, Infinite Lips)

Acc = [c, d, e]

Yes
6 ?- time(get_sublist_old(2, 3, [a, b, c, d, e, f], Acc)).
% 37 inferences, 0.00 CPU in 0.00 seconds (0% CPU, Infinite Lips)

Acc = [c, d, e]

Let’s try with bigger numbers…

24 ?- make_list(100000, L), time(get_sublist(2000, 500, L, Acc)).
% 378,001 inferences, 0.33 CPU in 0.42 seconds (78% CPU, 1145458 Lips)

L = [100000, 99999, 99998, 99997, 99996, 99995, 99994, 99993, 99992|...]
Acc = [98000, 97999, 97998, 97997, 97996, 97995, 97994, 97993, 97992|...]

Yes
25 ?- make_list(100000, L), time(get_sublist_old(2000, 500, L, Acc)).
% 15,007 inferences, 0.08 CPU in 0.09 seconds (87% CPU, 187587 Lips)

L = [100000, 99999, 99998, 99997, 99996, 99995, 99994, 99993, 99992|...]
Acc = [98000, 97999, 97998, 97997, 97996, 97995, 97994, 97993, 97992|...]

Yes
26 ?- make_list(100000, L), time(get_sublist_old(2000, 5000, L, Acc)).
% 42,007 inferences, 0.56 CPU in 0.66 seconds (85% CPU, 75013 Lips)

L = [100000, 99999, 99998, 99997, 99996, 99995, 99994, 99993, 99992|...]
Acc = [98000, 97999, 97998, 97997, 97996, 97995, 97994, 97993, 97992|...]

Yes
27 ?- make_list(100000, L), time(get_sublist(2000, 5000, L, Acc)).
% 7,530,001 inferences, 6.88 CPU in 8.82 seconds (78% CPU, 1094477 Lips)

L = [100000, 99999, 99998, 99997, 99996, 99995, 99994, 99993, 99992|...]
Acc = [98000, 97999, 97998, 97997, 97996, 97995, 97994, 97993, 97992|...]

Yes

It looks like we didn’t optimize very much. 😦
I should study more.


Ruby vs. Python? [no, Ruby vs. Ruby ]

February 20, 2006

In fact this is not a Ruby vs. Python list. I know not enought Ruby and I love Python to much :). It’s more a picture of the first impressions I had on Ruby after I seriously began studying it.

This is a quick list of thoughts. I’m probably adding more stuff later. In fact I’m reaaly amazed. Ruby is really hackish, but it’s also neat and clean. It may sound strange… but I’m afraid I’m gonna love ruby more than Python: it addresses many of the things I come to dislike in Python.

Some stuff I like

  • Adding dynamically stuff to classes. The syntax is clean and obvious
    class MyClass
      def aMethod
        puts "Called aMethod"
      end
    end
    
    m = MyClass.new
    
    begin
      m.aMethod2
    rescue NoMethodError => ex
      puts "Failed to call #{ex}"
    end
    
    class MyClass
      def aMethod2
          puts "Called aMethod2"
      end
    end
    
    m.aMethod2

    In Python for example it is not that clean. The ruby code looks more like ObjectiveC categories (even if in fact you don’t specify a category, of course, since ruby does not need categories).

  • private, protected, public modifiers. Being dynamic they do not limit me in any way (if I need I can dynamically change this)
    class MyClass
      protected
      def aMethod
        puts "Called aMethod"
      end
    end
    
    m = MyClass.new
    
    begin
      m.aMethod
    rescue NoMethodError => ex
      puts "Failed to call #{ex}"
    end
    
    class MyClass
      public :aMethod
    end
    
    m.aMethod

    Moreover I can’t think to a cleaner syntax to do this. Of course one can argue that they aren’t really necessary. Of course, but if you want they do give you a little bit of control, but they don’t limit you in any way.

  • Object#freeze: if you suspect that some unknown portion of code is setting a variable to a bogus value, try freezing the variable. The culprit will then be caught during the attempt to modify the variable.
  • I love postfixed control clauses. In fact if used with moderation they can augment code readbility (and of course if abused they make it less readable). However, it is pretty logigal to say do_something if something_else. In fact since ruby has blocks it is ok also to write
    begin
        # some stuff
    end if condition
    

    maybe not everyone agrees

  • Accessors are great. Using attr and similar constructs is great. I also find quite more readable to “assign” with foo= than using more Javesque setFoo(val). In fact properties in Python work in a similar fashion, even if maybe a bit more verbose (however, I think they make it clearer how to document code, but this is a ruby aspect I’ve not yet exploited)
  • Gems: I think python needs something like that. Pimp is not that good, in my opinion, of course.

Stuff I don’t know if I like or not

  • Not having to write parentheses with no-argument methods. I’ve not yet discovered if I like it or not.
  • All the $_… They are used a lot in Perl. I like it, but I’m afraid it can mess things up.

Stuff I dislike

  • I don’t like passing strings to require. In fact it can have advantages, but I prefer the pythonic import foo to require "foo".
  • The try catch semantic of try/catch, makes me think to some kind of disguised goto. I’m sure I’m wrong… but
  • I’d like to have something like Perl use strict;. It’s something I miss in Python (even if with pychecker you can just live without it). Now I’ve got to find some kind of “use strict” or “rubycheck”.
  • Assignment is an expression. This directly leads to code like
    a = true
    b = false
    print b if b=a
    

    and we imagine the programmer wanted to write

    a = true
    b = false
    print b if b==a
    

    However in Ruby almost everything is an expression, and it has quite a lot of advantages. So we have to tolerate the “=” for “==” problem.


Ruby 0.0

February 17, 2006

Today I decided to take some time and have a look at Ruby. I found online a version of Programming Ruby and started reading it. In fact I knew I was going to like Ruby. In fact the first time I took contact with it I quite liked it, even if I didn’t fully exploit its capabilities.

Well… let’s see how it goes. Right at the moment the first thing I wrote is

class Employee
  attr_reader :wage, :name
  attr_writer :wage
  
  def initialize(name, surname, wage)
    @name = name
    @surname = surname
    @wage = wage
  end
  
  def surname
    @surname
  end
  
  def to_s  
    "#{name} #{surname} (#{wage})"
  end
  protected :wage=
  
end

class Manager > Employee
  def initialize(name, surname, wage, employees=[])
    super(name, surname, wage)
    @employees = employees
  end
  
  def setWage(emp, wage)
    emp.wage = wage
    emp
  end
   
  def to_s
    super + @employees.collect{|e| "\n  #{e}"}.join("")
  end
end

mr = Employee.new("Jack", "Bravo", "1000€")
mc = Employee.new("Michael", "Charlie", "300€")
mngr = Manager.new("Angus", "Smith", "10000€", [mr, mc])
mngr.setWage(mc, "700€")
puts mngr

Stattoo

February 14, 2006

Stattoo è una piccola utility fatta da Panic. Uno dei più celebri prodotti di Panic è Transmit, a detta di molti il miglior client FTP per Mac (io personalmente sono affezionato a Fetch, che come studente posso avere in licenza gratuita e che ho usato fin dalla versione 1.x nei primi anni ’90, ma i meriti di Transmit sono indubbi).

Un’altra applicazione di Panic è Unison, ottimo newsreader per gruppi binari (per i le discussioni francamente lo trovo abbastanza povero, ma si stanno attrezzando). Ad ogni modo, ora è il turno di “Stattoo”. Il prezzo è 12.9 $. L’applicativo stampa sul desktop alcune informazioni con una bella veste grafica.

Stattoo Example

Per ora sono disponibili:

  1. Ora
  2. Data
  3. Appuntamenti di iCal
  4. Ultime Mail di Mail o di un qualunque account pop/imap anche non specificato in Mail
  5. Lo stato di iTunes
  6. Lista degli ultimi software arrivati su VersionTracker
  7. Spazio occupato sui vari dischi
  8. Temperatura locale
  9. Stato della batteria

La maggior parte di queste features sono ottenibili in altro modo. Spesso con dei widget o dei programmi. Tuttavia Stattoo è molto più veloce di Dashboard e cerco di tenerci quanta più roba possibile.

Varrebbe la pena di comprarlo anche solo per i punti 3 e 4. E anche la batteria è comodissima. Inoltre si può “sollevare” Statoo in trasparenza sopra le altre finestre schiacciando un tasto.

stattoo2.jpg

La cosa che però mi ha fatto decidere definitivamente per l’acquisto è stata la professionalità. Ho inviato una email facendo presente che per la mia città (Parma) non era disponibile un codice areoportuale ICAO (per le città non-USA viene usato questo per identificarle) e quindi non potevo usare il modulo “Weather”.

In effetti non è che la mia città non avesse un codice ICAO, solo il sito da Panic consigliato per scoprire tali codici presentava solo il codice IATA (un’altra sigla, poco importa cosa siano effettivamente). Ho mandato una email per chiedere consigli, dicevo.

Un gentilissimo dipendente (o forse proprietario o programmatore) mi ha risposto dicendomi il codice ICAO della mia città. Ovviamente funziona tutto. Immagino che in caso di problemi (all’epoca non ero ancora registrato) siano altrettanto celeri. E questo deve essere il valore aggiunto delle piccole case software: idee, ben realizzate e rapporto “umano” con il cliente.


Window Shade X

February 12, 2006

Credo di non avere mai decantato pubblicamente questo piccolo software. Lo registrai per la modica cifra di 10 $ (molto moderate. Quando un programma è buono e mi piace, lo compro, anche se è commerciale [ posto che me lo possa permettere ]. Questo è ancora più valido se si tratta di software di piccole case o singoli sviluppatori che mettono passione nel loro lavoro.
È il caso di TextMate di Allan Odgaard e di BBEdit (questa per esempio è una media software house che si dedica da anni a sviluppare ottimo software per Mac). È il caso di Yojimbo, sempre di BareBones (questo lo sto ancora valutando nei 30 giorni di prova). È il caso di GraphicConverter, che ho usato a sorti alterne credo fin dalla versione 1 sui miei vecchissimi Mac (e adesso uso in quanto la licenza viene pagata da Apple se acquisto un Mac di fascia “pro”). È il caso di MacSOUP (anche se ultimamente mi sto stancando di quanto poco sia “aquoso“, d’altra parte è uno di quei programmi che la licenza la paghi una volta e poi lo usi sempre).

Beh… fra questi ottimi software ci sono anche un paio di utility di Unsanity. Mi riferisco in particolar modo a FruitMenu e a WindowShade X. Dei due quello che uso più di frequente è senza dubbio il secondo. Altre utility interessanti di Unsanity sono ShapeShifter per cambiare il tema al MacOS e MenuMaster che sto valutando.

Window Shade X

Una delle cose che meno tollero di MacOS X è il dock. Lo trovo una brillante idea terribilmente sprecata. Al di la di ovvi problemi di coerenza di interfaccia (ad esempio al di la del separatore ci stanno finestre minimizzate, documenti, cartelle e cestino, mentre a mio avviso almeno le finestre dovrebbero essere da un’altra parte). Dicevo, le finestre da un’altra parte anche per ragioni di spazio.
Se si minimizzano molte finestre il dock si allunga e diviene quasi ingestibile. Questo problema viene risolto brillantemente da WindowShade X. Infatti permette di “minimizzare le finestre sul desktop: cosa intendo? Guardate l’immagine.

windowshade1.png

In questo modo posso facilmente minimizzare le finestre (posso anche spostarle sul desktop come fossero icone). Per esempio posso “rebindare” il pulsantino giallo per fare questo e continuare a minimizzare sul dock con Mela-M.
Per chi se lo stesse chiedendo… si, la minimizzazione sul desktop è simile a quello che fanno alcuni window manger sotto X11, per esempio twm [ ovviamente in modo oltremodo più raffinato, come si può vedere dall’immagine ] oppure il mio amatissimo WindowMaker. Triste che oggi ci si sia tutti o quasi omologati su sistemi molto più pesanti anche su GNU/Linux (senza nulla togliere a GNOME e KDE, solo meno  “originali”, per come la vedo io).
Un’altra funzione davvero comoda (la maggior parte delle volte uso questa) è minimizzare una finestra alla sua barra del titolo facendo doppioclick sulla stessa. Questo c’era in MacOS 9 e Apple lo ha (stupidamente?) tolto in MacOS X. È qualcosa presente anche su molti wmanager per X11, metacity per citarne uno.
Il tutto coopera perfettamente con Exposè e rende lavorare con molte finestre davvero comodo.

Altre funzioni sono quelle di fare diventare trasparente una finestra oppure di renderla “floating” sopra tutto il resto (per esempio una chat, un player audio minimizzato, boh). Insomma… davvero geniale WindowShade X.