Objetos mutáveis e imutáveis
Objetos mutáveis são objetos cujo estado pode mudar. Objetos imutáveis são objetos cujo estado nunca se altera após sua criação.
Objetos imutáveis têm muitas propriedades desejáveis:
No Ruby, a mutabilidade é uma propriedade de uma instância, não de uma classe completa. Qualquer instância pode se tornar imutável chamando o método freeze (congelar).
O método freeze na classe Objetct previne você de alterar um objeto, efetivamente transformando um objeto em uma constante. Após congelarmos um objeto, uma tentativa de modificá-lo resulta em um erro RuntimeError. O programa seguinte p050xfreeze.rb ilustra isso:
1 str = 'Uma string simples. ' 2 str.freeze 3 begin 4 str << 'Uma tentativa de se modificar.' 5 rescue => err 6 puts "#{err.class} #{err}" 7 end 8 # A saída é - TypeError can't modify frozen string
Entretanto, freeze opera na referência de um objeto, não em uma variável. Isso significa que qualquer operação resultando em um novo objeto funcionará. Isso pode ser verificado pelo seguinte exemplo:
1 str = 'String original - ' 2 str.freeze 3 str += 'anexo' 4 puts str 5 # A Saída é - String original - anexo
A expressão str += ‘anexo’ é avaliada para um novo objeto, que é então associado a str. O objeto não é alterado, mas a variável str agora se refere a um novo objeto.
O método frozen? lhe diz se um objeto está congelado ou não. Vamos ver um exemplo:
1 a = b = 'String Original' 2 b.freeze 3 puts a.frozen? # true 4 puts b.frozen? # true 5 a = 'Nova String' 6 puts a 7 puts b 8 puts a.frozen? # false 9 puts b.frozen? # true
Vamos entender o que estamos fazendo aqui – a e b são duas variáveis que apontam para um objeto do tipo string – String Original.
Nós então congelamos o objeto String Original. Portanto, tanto a quanto b agora apontam para o objeto congelado String Original. Isto é verificado pelas declarações puts a.frozen? e puts b.frozen?. Em seguida, criamos um novo objeto string Nova String e fazemos a variável a apontar para esse novo objeto. A variável b ainda aponta para o objeto congelado e a não mais. Isto é verificado pelas duas últimas declarações do programa.
Uso:
O Ruby às vezes copia objetos e congela as cópias. Quando você usa uma string como chave hash, o Ruby na verdade copia a string, congela a cópia e usa a cópia como chave hash: desse modo, se a string original se alterar mais tarde, a chave hash não é afetada.
As operações internas de arquivos do Ruby trabalham com uma cópia congelada do nome do arquivo ao invés de usar o nome do arquivo diretamente. Se outra thread altera o nome original do arquivo no meio de uma operação que deveria ser atômica, não há problema: o Ruby não estava usando o nome do arquivo original. Você pode adotar esse padrão copia-e-congela em código com suporte multi-thread para prevenir que uma estrutura de dados com que você esteja trabalhando seja alterada por outra thread.
Outro uso comum no nível do programador dessa funcionalidade é congelar uma classe para prevenir modificações futuras a mesma.
Nota: Sempre que um objeto no Ruby não tem referência a ele, então o objeto será marcado para remoção e o coletor de lixo irá remover esse objeto baseado em seu algoritmo. Não há como acessar um objeto sem referência.
Listei todos os pontos importantes para você se lembrar após ter completado os seguintes tópicos: Duck Typing, Açúcares sintáticos e Objetos Mutáveis e Imutáveis.
Este material tem como base o tutorial do RubyLearning.com de Satish Talim e foi traduzido por membros do GURU-SP com a permissão do autor.
Ajude o RubyLearning participando em algum dos cursos pagos ou fazendo uma doação para o projeto