o que a mensagem está passando no OO?

35

Eu estudei programação OO, principalmente em C ++, C # e Java. Eu pensei que tinha uma boa noção sobre isso com meu entendimento de encapsulamento, herança e polimorfismo (além de ler muitas perguntas neste site).

Uma coisa que parece surgir aqui e ali é o conceito de "passagem de mensagem". Aparentemente, isso é algo que não é usado durante a programação OO nas principais linguagens de hoje, mas é suportado pelo Smalltalk.

Minhas perguntas são:

  • O que é a passagem de mensagens? (Alguém pode dar um exemplo prático?)
  • Existe algum suporte para essa "mensagem que passa" em C ++, C # ou Java?
Tom
fonte
4
Eu respondi a essa pergunta no SO um tempo atrás: stackoverflow.com/a/3104741/10259
Frank Shearar
11
Você leu o artigo da Wikipedia ?
yannis
4
Na minha humilde opinião, o Objective-C se qualificaria como uma linguagem convencional. Pelo menos tanto quanto C #.
Mouviciel 20/03/12
Eu concordo com isso, eu estava declarando os idiomas "mainstream" da minha experiência
Tom
Uma chamada de função de membro é uma implementação de passar uma mensagem. A mensagem passada é identificada pelo nome da função e inclui as informações dos parâmetros. A ligação tardia permite que a classe receptora manipule a mesma mensagem de uma maneira diferente de outras classes. Não é o que os criadores do Simula pretendiam, e muitas pessoas se opõem a chamá-lo de passagem de mensagens e afirmam (com boas razões) que fazer a passagem de mensagens é uma coisa essencial que torna o Simula diferente, mas as chamadas de função de membro ainda fazem essencialmente o mesmo trabalho.
Steve314

Respostas:

60

O que é a passagem de mensagens? (Alguém pode dar um exemplo prático?)

A passagem de mensagens significa simplesmente que (em um nível muito abstrato) o mecanismo fundamental da execução do programa são objetos enviando mensagens uns aos outros. O ponto importante é que o nome e a estrutura dessas mensagens não são necessariamente fixados previamente no código-fonte e podem ser informações adicionais. Esta é uma parte importante do que Alan Kay originalmente imaginou como "programação orientada a objetos".

Existe algum suporte para essa "mensagem que passa" em C ++, C # ou Java?

Esses idiomas implementam uma versão limitada da mensagem passando por chamadas de método. Limitado porque o conjunto de mensagens que podem ser enviadas é limitado aos métodos declarados em uma classe. A vantagem dessa abordagem é que ela pode ser implementada com muita eficiência e permite uma análise estática de código muito detalhada (o que resulta em todos os tipos de benefícios úteis, como a conclusão de código).

Por outro lado, as linguagens que implementam a passagem de mensagens "real" geralmente também possuem definições de método, como uma maneira conveniente de implementar manipuladores de mensagens, mas permitem que as classes implementem manipuladores de mensagens mais flexíveis que permitem ao objeto receber "chamadas de método" com nomes arbitrários (não corrigidos em tempo de compilação).

Um exemplo no Groovy que demonstra o poder desse conceito:

def xml = new MarkupBuilder(writer)
xml.records() {
  car(name:'HSV Maloo', make:'Holden', year:2006) {
    country('Australia')
    record(type:'speed', 'Production Pickup Truck with speed of 271kph')
  }
}

irá produzir este XML:

<records>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'>Production Pickup Truck with speed of 271kph</record>
  </car>
</records>

Note-se que records, car, countrye recordsão sintaticamente chamadas de método, mas não existem métodos de que o nome definido no MarkupBuilder. Em vez disso, ele possui um manipulador de mensagens catchall que aceita todas as mensagens e interpreta os nomes das mensagens como o nome de um elemento XML, os parâmetros como atributos e os fechamentos como elementos filhos.

Michael Borgwardt
fonte
+1 direto ao ponto de resposta. Aceito para o exemplo de código. Obrigado pela vossa ajuda :)
Tom
Portanto, não poderia ser simplesmente implementado com uma linguagem simples sendMessage(property_name, Array of arguments)e getMessage(property_name, Array of arguments)estática?
Pacerier
11
@ Pacerier: claro, mas isso combina as desvantagens de ambas as abordagens - você perde a segurança do tipo e ainda tem o "sendMessage" poluindo seu código em todos os lugares, para não ter a sintaxe elegante.
Michael Borgwardt
Seria mais correto dizer que, no exemplo do Groovy, o manipulador de mensagens está recebendo uma mensagem, em vez de uma chamada de método? Você inicialmente coloca aspas na frase "chamada de método", mas na sua última frase, diz que "aceita todos os métodos ", em vez de "mensagens".
Adam Zerner
@ AdamZerner: você está certo, eu consertei.
Michael Borgwardt
28

A passagem de mensagens é uma maneira diferente de lidar com a necessidade no código OO de um objeto fazer com que outro objeto (ou potencialmente ele mesmo) faça alguma coisa.

Na maioria das linguagens modernas que descendem da abordagem C ++, fazemos isso com chamadas de método. Nesse caso, o objeto chamado (por meio de sua definição de classe) coloca uma grande lista do método que ele aceita e, em seguida, o codificador do objeto que chama chama simplesmente a chamada:

public void doSomething ( String input )
...
other_object.dosomething ( local )

Para linguagens de tipo estaticamente, o compilador pode verificar o tipo de coisa que está sendo chamada e confirmar que o método foi declarado. Para idiomas digitados dinamicamente, isso é realizado em tempo de execução.

Mas, em essência, o que acontece é que um pacote de variáveis ​​é enviado para um bloco de código específico.

Passagem de mensagem

Em linguagens de transmissão de mensagens (como o Objetivo C), em vez de métodos, existem receptores, mas, de maneira geral, a abordagem para defini-los e chamá-los é praticamente a mesma - a diferença é a maneira como são manipulados.

Em uma linguagem transmitida por mensagem, o compilador pode verificar se o destinatário que você chamou existe, mas, na pior das hipóteses, ele exibirá um aviso para dizer que não tem certeza de que está lá. Isso ocorre porque, em tempo de execução, o que acontecerá é que um bloco de código no objeto receptor será chamado passando o pacote de variáveis ​​e a assinatura do destinatário que você deseja chamar. Esse bloco de código procura o receptor e o chama. No entanto, se o receptor não existir, o código simplesmente retornará um valor padrão.

Como resultado, uma das esquisitices encontradas ao passar de C ++ / Java -> Objetivo C é entender que você pode "chamar um método" em um objeto que não foi declarado no tipo de tempo de compilação e nem sequer existia em o tipo de tempo de execução ... e que a chamada não resultaria em uma exceção, mas na verdade um resultado seria devolvido.

As vantagens dessa abordagem são que elas nivelam a hierarquia da subclasse e evitam a maioria das necessidades de interfaces / herança múltipla / tipos de patos. Ele também permite que os objetos definam o comportamento padrão quando solicitados a fazer algo para o qual eles não têm um receptor (normalmente "se eu não fizer isso, encaminhe a solicitação para esse outro objeto"). Ele também pode simplificar a vinculação a retornos de chamada (por exemplo, para elementos da interface do usuário e eventos programados), especialmente em linguagens de tipo estatístico, como Java (para que o botão chame o receptor de "runTest" em vez de chamar o método "actionPerformed" na classe interna "RunTestButtonListener", que faz a chamada para você).

No entanto, parece que está à custa da necessidade de verificação adicional pelo desenvolvedor de que a chamada que eles pensam estar fazendo está no objeto certo com o tipo certo e passando os parâmetros certos na ordem certa, porque o compilador pode não avisá-lo e ele funcionará perfeitamente bem em tempo de execução (retornando apenas uma resposta padrão). Também há, sem dúvida, um impacto no desempenho com a pesquisa extra e a passagem de parâmetros.

Atualmente, os idiomas digitados dinamicamente podem oferecer muitos benefícios da mensagem passada OO com menos problemas.

Gavin H
fonte
11
Eu gosto desta resposta - explica as diferenças e suas implicações.
HappyCat
@ Gavin, então é exatamente o mesmo que o manipulador de métodos dinâmicos do PHP e Javascript ?
Pacerier
11

As arquiteturas de transmissão de mensagens são simplesmente sistemas em que cada componente é independente dos outros, com um mecanismo comum para transmitir dados entre eles. Você pode considerar as chamadas de método como uma forma de passagem de mensagens, mas não é prático fazê-lo - isso confunde o problema. Isso ocorre porque se você tem uma classe com métodos bem definidos e algum código que chama esses métodos, a coisa toda deve ser compilada, acoplando o código e o objeto. você pode ver como está próximo (quando uma mensagem está sendo passada e o compilador está aplicando a correção, mas perde grande parte da flexibilidade de um sistema dissociado).

As arquiteturas de transmissão de mensagens geralmente permitem que objetos sejam adicionados em tempo de execução e, mais frequentemente, permitem que as mensagens sejam redirecionadas para um ou mais objetos. Para que eu possa ter algum código que transmita uma mensagem 'dados x são atualizados' para todos os objetos que foram carregados no sistema, e cada um deles pode executar qualquer ação que desejar com essas informações.

Um exemplo estranho é a web. HTTP é um sistema de transmissão de mensagens - você passa um verbo de comando e um 'pacote de dados' para um processo do servidor. (por exemplo, GET http: \ myserver \ url) Nem o seu navegador nem o servidor da web se preocupam com os dados que você envia ou para onde os envia. O servidor o passará para o código que irá empacotar outro 'pacote' de dados e o enviará de volta para você. Nenhum componente deste sistema sabe algo sobre o trabalho dos outros ou o que eles fazem, apenas conhece o protocolo usado para a comunicação da mensagem.

gbjbaanb
fonte
@gbjbannb, Precisa de algumas explicações de código pseudo ....
Pacerier