Terça-feira, Janeiro 26, 2010

Aniversário!

Dia 31 na Drinkeria Maldita!

Funções/Objetos

Hoje vi em uma base de código-fonte uma função cujo nome é "signalCatcher" -- um substantivo. A regra geral de estilo é: dados são chamados por substantivos, funções por verbos no infinitivo.

Mas faz sentido que "signalCatcher" seja o nome daquilo que você vai entregar ao mecanismo de sinais para tratar os sinais da aplicação, certo?

Eu acredito que a linguagem de programação do futuro não deve fazer distinção entre objetos-dados e objetos-função, mesmo sintaticamente; ambos ocupam espaço na memória e portanto exigem alocação, e são mencionados através de referências.

Em C, todas as funções são efetivamente objetos imutáveis, mas houve o tempo em que funções não eram imutáveis; esse tempo poderia voltar. E apesar de a maioria dos objetos ser mutável, alguns objetos são propositalmente imutáveis, e seus projetistas procuram maneiras de armazená-los em ROM.

Uma função deve ser um objeto cujo tipo é função, um tipo genérico variando na lista de parâmetros e na lista de resultados. O valor de um objeto do tipo função deve ser interpretado como uma sequência de instruções para o processador alvo, organizada de acordo com uma convenção de chamada apropriada. Esta convenção apóia a operação fundamental que o programa realiza sobre o objeto, chamar.

É claro que, ainda assim, uma função é um objeto bem especial. Em particular porque não é um objeto cujo tamanho é regular -- não se pode saber qual é o tamanho de um objeto função apenas conhecendo seu tipo.

Quarta-feira, Janeiro 13, 2010

Procurando apartamento!

Estou procurando apartamento no Rio de Janeiro.
Se souber de algo, avise!

Programação e Semiótica 7

Um novo exemplo para diminuir o tédio dos leitores e usar esses conceitos para entender o processamento de texto nos computadores.

Falemos sobre um programa que, por sua vez, deseja falar sobre textos em linguagem natural. Este programa fará referência a objetos cujo interpretante é "texto em linguagem de gente".


O que é texto em linguagem de gente? É uma sequência de símbolos que os seres humanos são capazes de entender como caracteres do seu idioma, que por sua vez se agrupam para formar palavras, frases etc. Nos idiomas latinos dizemos que as letras se agrupam para formar palavras; em idiomas como o japonês muitas vezes apenas um caracteres já é uma palavra inteira.

Mas o computador não sabe nada sobre caracteres, apenas sobre números. Com certeza o computador é capaz de representar na memória números uns na frente dos outros.


A intuição fundamental é a possibilidade de estabelecer um mapa de caracteres onde cada caractere está mapeado para um número e vice-versa. Formalmente, o mapa é uma função bijetora entre os conjuntos "números inteiros" e "caracteres".

Assim, um programa processador de texto faz referência a objetos cujo primeiro tipo é "número inteiro" e cujo segundo tipo é "caractere do mapa tal".

Suponha o seguinte mapa: a = 1, b = 2, c = 3 etc. O texto "abc" seria um objeto composto por três objetos numéricos contíguos 123.

Como poderia um programa colocar palavras em ordem alfabética? Toma dois objetos "palavra" e compara os dois caracteres iniciais como números; se forem diferentes, a ordem é numérica; se forem iguais fazemos a mesma coisa com o segundo caractere e assim por diante. Essa é a ordenação lexicográfica.

Esse esquema é interessante quando podemos usar um objeto de tamanho fixo e tipo "número" para todos os caracteres desejados. Mas com o advento da Internet e a interligação entre sistemas de todo o mundo se tornou inviável usar mapas de caracteres pequenos.

O que acontece quando um sistema do Japão envia 123 para um sistema do Brasil? Que mapa de caracteres o sistema do Brasil deve tomar como interpretante desses números? Essa dificuldade é a causa de muitos fenômenos bizarros na Internet, onde páginas mostram um monte de lixo onde deveriam estar caracteres latinos acentuados ou coisa parecida.

A primeira lição da interligação de sistemas processadores de texto é que não existe objeto "texto" compreensível sem um interpretante "mapa de caracteres" associado. Essa associação é um problema que sempre deve ser resolvido, mesmo que a solução seja um contrato entre todas as partes definindo um e apenas um mapa válido. Esse tipo de contrato não se mostrou viável a longo prazo.

Alguns sistemas de programação experimentaram construir tipos mais complexos para objetos; não apenas "texto" mas "texto ASCII" ou "texto ISO-8859-1" -- embutindo no tipo do objeto também o tipo do mapa de caracteres. Isso é interessante para apoiar contratos como o anterior, mas um pouco estranho quando o sistema deve aceitar diversos tipos de texto de diversas partes do mundo.

Estas parecem as coisas básicas que sempre queremos fazer com texto: contar o número de caracteres, decidir se dois textos são iguais, decidir qual de dois textos deve aparecer antes na ordem do dicionário, e inspecionar o texto letra por letra (para imprimir na tela, por exemplo). Com os mapas numéricos simples, podemos fazer todas essas coisas simplesmente trabalhando com pares de números: os primeiros de cada texto, depois os segundos de cada texto, etc.

Nesses mapas, existe uma referência sensata que atravessa a representação dos objetos da mais pura -- os números -- para a mais abstrata -- o caractere do texto.

Essa facilidade eventualmente terminou, o que ainda parece muito traumático para programadores acostumados com essa situação tão segura.


Eventualmente a comunidade internacional decidiu dar um basta na multiplicidade dos mapas e resolveu produzir o super-mapa Unicode. Este mapa é um catálogo de praticamente todos os caracteres usados na galáxia, associados cada um deles a um número inteiro positivo. Infelizmente, são muitos caracteres, que não podem ser representados com números pequenos.

A princípio, os indivíduos decidiram usar números grandes e manter o esquema de mapa com objetos de tamanho fixo. Assim, o processamento par-a-par continuaria possível. Mas os objetos texto explodiram de tamanho e essa esquema se mostrou inviável.

Então um compromisso foi firmado: um novo mapa foi produzido para o Unicode onde quase 90% dos textos continuaria com o mesmo tamanho, e apenas 10% seria maior. Este mapa às vezes usa um número por caracteres, às vezes dois, às vezes três e às vezes quatro. Este simples fato é o pesadelo dos programadores novatos de processamento de texto.

Por que este mapa UTF-8 possui uma representação tão estranha com objetos caractere de tamanho variável, deixou de ser sensata a referência direta número-a-caractere. Um sistema que recebe 1234 3456 5678 e deve interpretar esses números como texto deve não mais assumir que o primeiro número é um caractere, e o segundo um caractere etc. É possível que na realidade os dois primeros números sejam um caractere juntos.

Uma sequência de números que deve ser interpretada como UTF-8 não pode mais ser percorrida ingenuamente número a número, e os algoritmos de processamento baseados em comparações par-a-par estão quebrados. Isso, novamente, se deve ao fato de que UTF-8 viola propositalmente premissas simples de significação dos números que compõe um texto.

Isso foi um problema grave porque programas antigos despreocupadamente tratavam seu texto de forma crua, diretamente com os números, confortados pelas premissas do processamento de texto -- ao invés de fazer isso com funções especiais em módulos de processamento de texto.

Quando o significado dos números foi alterado nos processos de substituição de mapa por mapa, consertar esses programas foi tarefa infernal. Os programas com funções especiais de tratamento de texto modificaram apenas estas funções e foram livrados deste mal.

Esta vitória do encapsulamento pode ser compreendida pelo encapsulamento de uma função sígnica -- a compreensão dos signos-número como signos-letra encapsulada em certos entes responsáveis, e uma transformação cultural pôde ser efetivada apenas instruindo estes entes responsáveis, e não todos os entes.

No final das contas o problema se tornou tão bem resolvido que surgiu um componente tão reusável que surge por toda parte, a libiconv.

Terça-feira, Janeiro 12, 2010

Programação e Semiótica 6

Entender o texto de um programa sob a ótica da semiótica é um pouco mais fácil do que entender outros tipos de texto porque o limiar de realidade do programa está bem delineado e bem próximo: a máquina.

Por essa razão, não é preciso uma poderosa metafísica para entender o que é um objeto, mesmo que este esteja, para o programa escrito, totalmente oculto.

Bolei o seguinte diagrama para descrever as três propriedades fundamentais de um objeto segundo as regras da máquina.


Estas três propriedades são a "base" de um objeto e o determinam completamente; seu estado ou padrão de bits, seu local ou endereço, seu tamanho ou comprimento em bytes.

Local e tamanho são propriedades espaciais, sendo a memória um universo unidimensional. Falamos sobre onde um objeto está, e ao longo de que comprimento. Estado é uma propriedade temporal, e (potencialmente) muda a cada instante.  Falamos sobre qual é o estado de um objeto (agora).



Mas eu venho insistindo que o programa escrito em linguagem de alto nível nada sabe sobre objetos, exceto aquilo que pode falar sobre eles através de referências, e tentando aplicar a nomenclatura da semiótica para dizer isso.

Bolei o seguinte diagrama para relacionar os três conceitos que eu estou tentando usar, que envolvem toda expressão no programa escrito sobre objetos.

Uma expressão em um programa escrito como "y = x + x" possui, além dos elementos sintáticos = e + os nomes y e x; estes nomes são tradicionalmente chamados variáveis e eu os estou chamando aqui de referências. Esses nomes significam objetos por intermédio de um tipo (que eu acredito ser equivalente ao interpretante.)

Linguagens como C++ prendem referência e tipo através da sintaxe; a ferramenta que interpreta o programa sempre sabe qual é o tipo associado a um nome como x. Linguagens como Javascript não prendem referência e tipo dessa forma, de modo que a ferramenta deve sempre considerar o contexto de uma expressão para inferir um tipo para x.

A vantagem do C++ (e similares) é a possibilidade de se apoiar em uma ferramenta para evitar que uma referência absurda seja formada e usada; linguagens como essa permitem a dedução da validade semântica a partir da validade sintática. Este é o sonho da análise estática de programas: descobrir erros no significado a partir do (uso da) sintaxe.

No seguinte exemplo em C++:

    complex c1 = { 1.0, 1.0 };

c1 é uma referência cujo interpretante estático é "número complexo". Conhecendo os segredos deste interpretante, poderíamos compreender o resto do texto, o próprio objeto, como o número complexo 1 + i.

A vantagem do Javascript (e similares) é a possibilidade de se expressar
sobre objetos através de múltiplos tipos viáveis de acordo com a conveniência; linguagens como essa simplificam a validade sintática para aumentar as opções de validade semântica.

No seguinte exemplo em Javascript:

   nome = "Pedro Lamarão";

nome é uma referência sem interpretante estático. Conhecendo os segredos da sintaxe da linguagem, saberíamos que aspas duplas implicam o interpretante "texto", e portanto nome significa o meu nome.

Independentemente de onde o leitor obtém um tipo-interpretante para uma variável-referência, é através deste que o objeto-estado possuirá uma conotação -- um significado imediato. Os três tipos fundamentais em máquinas contemporâneas são o inteiro-sem-sinal, o inteiro-com-sinal e o ponto-flutuante.

Programas do mundo real, porém, estão muito interessados em coisas como letras, textos, nomes de pessoas e lugares, valores em moeda local, fotos etc. Diversos programas precisam impor significados adicionais a objetos fundamentalmente aritméticos para serem úteis.

Essa necessidade nos leva naturalmente a pensar em objetos compostos por objetos simples e sobre a diferença conceitual entre um objeto na máquina concreta e um valor em um conjunto abstrato. Certos programas dirão que um certo objeto possui o valor "Pedro Lamarão" -- mesmo sabendo que a máquina fundamentalmente só compreende números.

O relacionamento entre as idéias objeto e valor, e a idéia de composição de objetos, torna o processo semiótico de um programa muito mais rico, interessante e passível de absurdos -- onde nem sempre se consegue responder com facilidade a perguntas simples como "x é igual a y?"

Quinta-feira, Janeiro 07, 2010

Semiótica e Programação 5

Agora, para um pensamento menos entediante.

Considere que autenticação é o processo pelo qual um sujeito se convence que um certo signo de fato significa um certo objeto -- uma certa credencial de fato significa um certo indivíduo, por exemplo.

Quando você ouve a campainha e alguém dizer "Olá" e pensa "Deve ser fulano" você autentica o signo vocal para se convencer ainda mais usando o olho mágico.

O método de autenticação em sistemas de informação com a interação mais simples é a checagem de um segredo compartilhado. O sistema conhece um segredo para um username e assume que se alguém apresentar o username e o segredo, então deve ser o significado daquele username.

O programa em execução, após executar essa interação com sucesso, construirá um objeto na memória, e manterá uma referência para ele cujo significado ulterior é username-do-usuário. Já que a autenticação foi bem sucedida, o programa confiará até terminar que esta referência é adequada, e poderá usá-la para julgar se deve ou deve não permitir o usuário a abrir certos arquivos etc.

Esta confiança no significado daquela referência é perfeitamente adequada para programas convencionais: a memória de um programa convencional em um sistema convencional é exclusiva, de modo que ele pode facilmente se convencer de que o objeto referenciado é íntegro.

Às vezes programadores movem para sistemas diferentes onde as regras são diferentes, e esse tipo de expectativa implícita é violada com consequências drásticas.

O jovem programador que move sua atividade para a web pode escrever um site em script que autentica o usuário e guarda o username em um objeto da sessão. O programa subjacente então continuamente fará certa referência a este objeto para tomar decisões de segurança, afinal, esta referência está para o objeto certo, não é?

Porém, neste ambiente, o programador não pode assumir a integridade do objeto -- não ingenuamente, como eu assumi acima. Como a web é um sistema bem distribuído e como o browser acessa o site um arquivo por vez, sem qualquer continuidade, este objeto ao qual o script faz referência não está sob seu controle. Ele existe em uma memória distante, fora do seu controle.

Fora do seu controle significa sob controle de um outro agente: o cliente. Suponha então que eu faça um acesso a uma página restrita e posicione arbitrariamente um objeto com o username de outra pessoa justamente no local onde a referência do programa assume que ele esteja. Assim, eu posso mentir ao programa sobre quem eu sou, me valendo de uma ingenuidade no significado do programa.

Perceber esse furo de segurança no site pode ser difícil porque o texto do programa do site pode adequadamente obter o username e compará-lo com regras de autorização em todos os lugares. O problema aqui é semanticamente anterior a esta comparação: o problema está na premissa de que uma certa referência está de fato para um objeto com o significado esperado.

Assim, os defeitos nos processos de autenticação em sistemas de informação são compreensíveis sob a ótica de uma função sígnica com "defeito" -- uma oportunidade através da qual o par em uma conversação tem condições de mentir. Concretamente, esse defeito existe no programa na forma de uma confiança indevida sobre o objeto de uma referência.

Quarta-feira, Janeiro 06, 2010

Semiótica e Programação 4

O padrão Proxy ocorre sempre que um objeto no sistema existe como substituto de outro objeto, por alguma razão. Em um sistema distribuído entre muitos computadores físicos, um objeto local pode ser substituto de um objeto que está em outro computador, ocultando o mecanismo de comunicação entre computadores.

O objeto proxy, de um modo ou de outro, possuirá uma referência ao objeto proxied; e o programa que possui uma referência ao objeto proxy possuirá uma referência ao objeto proxied.

Esses múltiplos níveis de indireção trazem problema para a expressão e compreensão do programa devido a frequente ausência de interpretantes para humanos -- também conhecidos como documentação.

Considere um objeto whatever que é um proxy para um objeto em um computador central, e uma rotina com essa aparência:

   get_name (whatever) -> (s1)
   ; s1 is the name of whatever

Um programa chama get_name e obtém uma referência ao objeto "nome" de um outro objeto qualquer.

Agora, resta a pergunta: se o programa que eu estou rodando modificar o valor de s1, o que acontece com whatever? Se Fulana rodar o mesmo programa depois que eu, que valor de s1 ela vai obter? s1 é uma referência para uma cópia ou é uma referência para o original?

Essa diferença é importante por razões que não apenas as consequências de modificar o objeto. A memória do computador é finita e portanto os programas devem cuidar de destruir os objetos que já acabaram de usar. Mas o que o programa que usa get_name deve fazer com o objeto referenciado por s1? Ele deve destruí-lo? Ele pode destruí-lo? Com certeza ele não pode destruir um objeto que está referenciado por diversos outros programas.

Por que (alguns) programas devem cuidar da presença dos objetos na memória, e dar manutenção nessa memória, existe sempre o problema de dispor de espaço para objetos ocuparem e por quanto tempo. Quando um programa faz algo como:

   string s4 = "Marcelinho"

a expressão de que "existe um s4 que é um texto" é interpretada implicitamente como "precisamos arranjar espaço para um texto pelo tempo necessário".

Quando o programa lida com objetos que foram criados por ele mesmo e são locais, o uso do espaço e do tempo é óbvio porque explícito; referências a objetos ocultos demandam maiores explicações.

As referências indiretas como os objetos proxies levam o problema além quando tornam possível que uma referência seja absurda -- uma referência a nenhum-objeto. Há programas onde faz sentido uma referência a nenhum-objeto e há programas onde isso não faz sentido. O programador deve deixar isso sempre claro sob pena de não ser compreendido.

Documentação é a única solução geral na medida em que linguagens de programação em geral não oferecem mecanismos sintáticos para se especificar esses atributos de uma referência.

Nem mesmo C++, que possui duas notações para referências com diversos graus de rigor sintático, consegue expressar tudo o que se deseja expressar, e a confusão sobre a especificação de "rvalue references" indica que ainda não está firmada a sintaxe do futuro.

Linguagens como Java, onde a quase totalidade dos objetos são criados por um gestor central em memória desconhecida, permitem ao programa ignorar a manutenção da memória mas ainda sofrem do problema de compreensão das referências.

Quando começamos a considerar as referências polimórficas a situação fica ainda mais punk.

Segunda-feira, Janeiro 04, 2010

URIs e a semiose da web

(TODO: Será que estou usando os termos certos? Suponho que "significante" seja o mesmo que "interpretante" mas a nomenclatura da Semiótica não está bem firme na minha memória.)

Existe bastante semiose na comunicação entre programas de computador, mesmo que seja uma semiose extremamente simples, com um universo de possibilidades bastante limitado.

O serumano ao acessar uma página na Web digita no browser: http://www.twitter.com/pedrolamarao -- uma URI.

Existe algo de muito interessante acontecendo entre o serumano, o browser e um servidor perdido na rede; algo descrito em grande pompa teórica na especificação das URIs.

Em primeiro lugar, esse texto é bastante opaco para a maioria das pessoas; muitas delas compreendem que "twitter" é o nome de um "site" e que estão querendo ver as paradas de "pedrolamarao".

Alguns mais acostumados com a Web sabem que "http" é o nome das coisas que são da Web, e que existem outros nomes próprios de outros programas, como "ftp".

Realmente esse texto, ou esse símbolo, se divide em duas partes, e deve ser interpretado em dois estágios, ou como composto de dois símbolos distintos.

O primeiro símbolo é "http" que deve ser interpretado de acordo com um esquema bem simples -- a pura comparação textual. "http" vai para cá, "ftp" vai para lá e assim por diante. O nome desse símbolo é schema e esse símbolo será o interpretante do símbolo seguinte: deve-se interpretar o resto do texto de acordo com este princípio do texto.

Existe uma infinitude de possíveis schemas, já que um schema é apenas e tão somente um monte de letras em sequência. Além disso, o acordo entre todos nós sobre o que um schema significa pode ou pode não ser bem definido; é claro que a Internet inteira concorda sobre o que é "http", mas duvido que algum de vocês saiba como interpretar "astrotv" da mesma forma que eu.

Quando o schema é "http" o sistema sabe que deve usar o browser Web. Ao menos, assim esperamos que seja, quando clicamos em "http://www.twitter.com/pedrolamarao" sublinhado em azul naquele email que recebemos. O browser Web, por sua vez, sabe que  o segundo símbolo -- "www.twitter.com/pedrolamarao" -- é composto também por diversos símbolos, quando a URI é "http".

O primeiro deste último conjunto é chamado authority e possui um entre poucos interpretantes aceitáveis. Neste caso, o domain name system ou DNS é o nome do sistema responsável. Este sistema dirá ao browser Web onde está o servidor responsável. Mais detalhes são irrelevantes. Restam poucos outros interpretantes aceitáveis, e seus sistemas são cheios de números.

O segundo deste último conjunto é chamado path. Este path possui um interpretante básico: o sistema de arquivos do servidor significado pelo authority. É o mesmo que os arquivos na máquina de qualquer pessoa. É claro que, como é da natureza do mundo, existem diversos outros interpretantes possíveis, como por exemplo algum outro programa dentro do servidor Web que mapeia "pedrolamarao" para um negócio em um banco de dados.

Porém, tudo o que o browser Web precisa saber, parte do seu acordo com o servidor Web, é que para qualquer path o servidor Web enviará uma porção de dados. Na maioria das vezes, esses dados estão de acordo com a norma  HTML ou CSS e devem ser interpretados através destas -- seus interpretantes. É claro que nem sempre é assim, já que vêm também scripts Javascript, fotos JPEG, música MP3 etc. etc.

Como o browser sabe qual será o interpretante mais adequado para cada um desses símbolos bizarros de 0s e 1s que vêm pela rede? A semiose durante um simples abrir de página é complexa e cheia de elementos, e será finita apenas até o ponto em que o engenheiro perder o interesse nos detalhes do sistema.

A cada passagem de símbolo a símbolo por um interpretante escolhido por qualquer agente nessa confusão toda há chance para algum problema. Administradores de servidor Web vivem às voltas com "página não encontrada" e arrancam os cabelos para entender porque um determinado path não foi encontrado. Volta e meia um browser Web resolve imprimir um monte de lixo na tela quando o usuário tem certeza que está baixando um filme. Às vezes um sujeito digita o nome de um site e o browser Web diz "nome não encontrado". O que acontece quando a configuração do DNS está com defeito!? E alguns infelizes usam sistemas que não tem muita certeza sobre o que fazer com nomes começando com "http".

Toda vez que surge um novo sistema de componentes na indústria há bravatas sobre o desenvolvimento de um novo tipo de "nome globalmente único". É o grande sonho da humanidade, ser capaz de nomear os entes sem ambiguidade. Todo um conjunto de sociedades esotéricas existe em desespero para aprender o Idioma de Adão, que soube nomear todas as coisas sem hesitação. Os humanos com senso prático compreendem que nomes são acordos entre as partes e estabelecem tais acordos entre si. O schema "http" por exemplo possui um significado em acordo estabelecido sob a autoridade do IANA. Mas você sabe o que IANA significa?..

Quarta-feira, Dezembro 30, 2009

Semiótica e Programação 3

Do ponto de vista do Java e do C#, C++ é uma linguagem fracamente tipada. Apesar de dizer isso abusar dos termos, existe um fundo de verdade ali.


C++, ao contrário de Java e C#, permite a formação de referências arbitrárias a qualquer objeto -- mesmo objetos hipotéticos.


Programas como este são aceitáveis, para o compilador:


list<string>* l = (list<string>*)0x12345;
l->sort();

Esta propriedade é inútil para a maioria dos programas, o que torna C++ excessivamente complicada aos olhos da maioria dos programadores. Se o programa está dizendo que naquele lugar ocorre um list<string> então isso deve ser verdade, certo? Boa sorte!

Existem programas que fazem uso dessa possibilidade, como programas para máquinas onde certos endereços são especiais e têm significado pré-definido.

Programas como este também são aceitáveis:

dog* marley = new dog();
spaceship* one = (spaceship*)marley;
one->launch();

Essa possibilidade é inerente à máquina, na medida em que o significante de uma referência existe apenas no mundo do discurso; a máquina conhece apenas bits. A reinterpretação de um padrão de bits é uma operação de pura semiótica: não é necessário computar nada, apenas compreender os bits de uma forma diferente. Assim sendo, C++ se limita a dizer que não fará esforço para garantir que esse programa faz sentido -- o problema é todo seu.

A estrutura que o tipo de uma referência impõe ao programa pode ser tal que nem todos os padrões de bits possíveis para aquele segmento de memória tenham um significado. Assim, apesar de o programa afirmar que ali está um objeto spaceship, o padrão de bits que ocorre ali pode não representar um objeto spaceship -- e o programa é literalmente um absurdo.

Em outras palavras, esse programa potencialmente viola invariantes do tipo spaceship, que são pré-condições automáticas para a chamada da função launch.

A reinterpretação irrestrita de objetos é uma das características mais estranhas dessa linguagem, e mais difícil de pôr em prática de forma útil.

Um desses usos é a transferência de objetos entre programas através de um dispositivo, técnica em que o programa receptor obtém uma pura sequência de bytes e assume que ali está o objeto transferido. Isso é chamado serialização porque torna o objeto, que possui significado e estrutura, em um série de bits.

Outro desses usos é a técnica de move construction do Elements of Programming, onde o objeto é reinterpretado de acordo com sua underlying class e copiado como tal -- e esta cópia é justamente a movimentação desejada.