puts [1, 2] <=> [2, 1] # -1 puts [1, 2] < [2, 1] # undefined method `<' for [1, 2]:Array (NoMethodError)
Pourquoi peut-on faire un test de comparaison entre deux tableaux (qui renvoie “inférieur”, “supérieur” ou “égal”), mais ne peut-on pas tester si l'un est inférieur à l'autre ? Plus étrange, pourquoi < ne repose-t-il pas sur l'implémentation de ⇔ ?
Ruby utilise les espaces pour décider de la priorité des opérations. “f -a” appelle la fonction f avec la valeur -a, tandis que “f - a” fait une soustraction. C'est très bien, car ça allège la syntaxe et ça correspond à ce que l'on voudrait. En revanche, on trouve rapidement des comportements surprenants, voire incohérents.
def sqrt(x) Math.sqrt x end sqrt(-2).abs # Plante comme prévu. sqrt (-2).abs # Fonctionne (valeur absolue de racine de 2) puts (-2).abs # affiche 2, OK Math.sqrt (-2).abs # génère une erreur : sqrt est appelé avec -2 ?!
Exemple de Wikipédia sur la portée :
int x = 0; int f () { return x; } int g () { int x = 1; return f(); }
Si on appelle g, un langage avec portée statique renverra 0, alors qu'un langage à portée dynamique (quasiment tous les langages ont abandonné ce concept) renverra 1. Essayons dans Ruby :
x = 0 def f() x end def g() x = 1; f() end puts g() a.rb:2:in `f': undefined local variable or method `x' for main:Object (NameError) from a.rb:3:in `g' from a.rb:4
Essayons avec des fonctions anonymes (il faut les appeler avec la méthode call… beurk !) :
x = 0 f = lambda {x} g = lambda {x = 1; f.call} puts g.call # Affiche 1
Ce n'est toutefois pas de la portée dynamique, c'est simplement que “x = 1” ne représente plus une déclaration, mais une affectation. La confusion déclaration/affectation est assez déroutante.
irb(main):053:0> ('1'..'15').to_a => ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"] irb(main):054:0> ('1'..'15').include?('10') => true irb(main):055:0> ('1'..'15').include?('9') => false irb(main):056:0> ('1'..'15').include?('123') => true