Skip to content

Instantly share code, notes, and snippets.

@FlaviaFortes
Last active April 5, 2016 22:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FlaviaFortes/f7060cc86c2e6f6a6d576e0ad09d712a to your computer and use it in GitHub Desktop.
Save FlaviaFortes/f7060cc86c2e6f6a6d576e0ad09d712a to your computer and use it in GitHub Desktop.
Disruptivo
def pp2 (attrs)
puts attrs
puts attrs.class
end
irb(main):024:0> pp2([a: "a", b: 1])
{:a=>"a", :b=>1}
Array
=> nil
irb(main):025:0> pp2({a: "a", b: 1})
{:a=>"a", :b=>1}
Hash
=> nil
##########
irb(main):046:0> t = { "a": 1, "b": 2, "c": 3 }
=> {:a=>1, :b=>2, :c=>3}
irb(main):047:0> t.fetch("a")
KeyError: key not found: "a"
irb(main):052:0> t.fetch(:a)
=> 1
irb(main):048:0> t.fetch(a)
NameError: undefined local variable or method `a' for main:Object
@andrewhr
Copy link

andrewhr commented Apr 5, 2016

No primeiro bloco o que eu imagino que esteja acontecendo é que implicitamente o parser do ruby está entendendo o seguinte:

pp2([{a: "a", b: 1}])

Dado o uso da sintaxe "açucarada" de mapas com chaves feitas de símbolos. Por que ele printa diferente já é um mistério para mim... talvez alguma ambiguidade com a feature de keyword arguments.

Já o segundo bloco é um pouco mais esperado, embora não menos mágico:

t = { "a": 1, "b": 2, "c": 3 }

é lido como

t = { :"a" => 1, :"b" => 2, :"c" => 3 }

e :"a" é outra forma de definir o símbolo :a. Por isso o primeiro fetch reclama e o segundo aceita de boas.

EDIT: confirmando, o primeiro caso é realmente ambiguidade com keyword arguments.

@FlaviaFortes
Copy link
Author

No primeiro bloco ele realmente entende como um Hash dentro de um Array. Se colocarmos o método p para printar, você percebe, ó:

Dado:

def pp2 (attrs)
  puts attrs
  p attrs
  puts attrs.class
end
irb(main):061:0> pp2([a: "a", b: 1])
{:a=>"a", :b=>1}
[{:a=>"a", :b=>1}]
Array
=> nil

@FlaviaFortes
Copy link
Author

O método puts remove os [] de um Array, exemplo:

irb(main):063:0> puts [1]
1

@FlaviaFortes
Copy link
Author

No segundo bloco:

O : é como chamar o método to_sym, então não funciona para qualquer valor:

irb(main):064:0> "a".to_sym
=> :a
irb(main):065:0> 1.to_sym
NoMethodError: undefined method `to_sym' for 1:Fixnum

@FlaviaFortes
Copy link
Author

O que torna as coisas engraçadas nesses casos:

irb(main):070:0> { 1=> "a", 2=> "b"}
=> {1=>"a", 2=>"b"}
irb(main):071:0> { 1: "a", 2: "b"}
SyntaxError: (irb):71: syntax error, unexpected ':'

@andrewhr
Copy link

andrewhr commented Apr 5, 2016

Imaginei que poderia ser algo na linha do seguinte:

  1. o parser tenta ler o valor como *args, fazendo o splat para uma array ou um argumento opcional, com isso ele captura o primeiro caso;
  2. em seguida ele tenta realizar o splat via **kwargs, entendendo que não há nenhum argumento exceto o hash final de chave-valor;

Faz algum sentido (ao menos na minha cabeça), imaginando uma implementação imperativa de como esse código é tratado. Infelizmente não consegui emular isso para um novo método. Talvez seja uma idiossincrasia do próprio puts, talvez seja problema por ele ser implementado de forma nativa... talvez eu esteja completamente errado e por isso não consegui replicar ¯_(ツ)_/¯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment