Pergunta

Posso especificar interfaces de quando eu declarar um membro ?

Depois de pensar sobre esta questão por um tempo, ocorreu-me que uma linguagem estática tipada-duck realmente pode funcionar. Por que não pode predefinidas classes de ser ligado a uma interface em tempo de compilação? Exemplo:

public interface IMyInterface
{
  public void MyMethod();
}

public class MyClass  //Does not explicitly implement IMyInterface
{
  public void MyMethod()  //But contains a compatible method definition
  {
    Console.WriteLine("Hello, world!");
  }
}

...

public void CallMyMethod(IMyInterface m)
{
  m.MyMethod();
}

...

MyClass obj = new MyClass();
CallMyMethod(obj);     // Automatically recognize that MyClass "fits" 
                       // MyInterface, and force a type-cast.

Você sabe de quaisquer linguagens que suportam esse recurso um? Seria útil em Java ou C #? É fundamentalmente falho de alguma forma? Eu entendo que você poderia subclasse MyClass e implementar a interface ou usar o padrão de projeto Adapter para realizar a mesma coisa, mas essas abordagens parecem apenas como código clichê desnecessário.

Foi útil?

Solução

linguagens estaticamente tipadas, por definição, verifique os tipos e marcas a tempo de tempo de compilação , não executar . Um dos problemas óbvios com o sistema descrito acima é que o compilador vai verificar tipos quando o programa é compilado, não em tempo de execução.

Agora, você poderia construir mais inteligência no compilador para que ele pudesse derive tipos, ao invés de ter o programador explicitamente declarar tipos; o compilador pode ser capaz de ver que implementa MyClass um método MyMethod(), e lidar com este caso em conformidade, sem a necessidade de declarar explicitamente as interfaces (como você sugere). Tal compilador pode utilizar tipo inferência, tais como Hindley-Milner .

É claro que algumas linguagens de tipagem estática, como Haskell já fazer algo semelhante para o que você sugere; o compilador Haskell é capaz de inferir tipos (na maioria das vezes) sem a necessidade de declará-los explicitamente. Mas, obviamente, Java / C # não tem essa capacidade.

Outras dicas

Uma marca nova resposta a esta pergunta, Go tem exatamente esse recurso . Eu acho que é muito legal e inteligente (embora eu vou estar interessado em ver como ele joga fora na vida real) e elogios sobre o pensamento dela.

Como documentado na documentação oficial (como parte do Tour of Go, com exemplo de código) :

Interfaces são implementadas implicitamente

tipo implementa uma interface através da implementação de seus métodos. Há sim nenhuma declaração explícita de intenções, não "implementa" palavra-chave.

interfaces de implícitas dissociar a definição de uma interface de seu implementação, o que poderia, então, aparecer em qualquer pacote sem prearrangement.

Como sobre o uso de modelos em C ++?

class IMyInterface  // Inheritance from this is optional
{
public:
  virtual void MyMethod() = 0;
}

class MyClass  // Does not explicitly implement IMyInterface
{
public:
  void MyMethod()  // But contains a compatible method definition
  {
    std::cout << "Hello, world!" "\n";
  }
}

template<typename MyInterface>
void CallMyMethod(MyInterface& m)
{
  m.MyMethod();  // instantiation succeeds iff MyInterface has MyMethod
}

MyClass obj;
CallMyMethod(obj);     // Automatically generate code with MyClass as 
                       // MyInterface

Eu não tenho realmente compilou este código, mas eu acredito que é viável e bastante trivial C ++ -. Ização do original proposto (mas folga) Código

Não vejo o ponto. Por que não ser explícito que os implementos de classe da interface e ter feito com ele? Implementando a interface é o que diz a outros programadores que esta classe é suposto a se comportar da maneira que define a interface. Basta ter o mesmo nome e assinatura em um método transmite há garantias de que a intenção do designer foi realizar ações semelhantes com o método. Isso pode ser, mas por que deixar isso para a interpretação (e abuso)?

A razão que você pode "fugir" com este sucesso em linguagens dinâmicas tem mais a ver com TDD do que com a própria linguagem. Na minha opinião, se as ofertas de linguagem a possibilidade de dar a estes tipos de orientação para outras pessoas que utilizam / visualizar o código, você deve usá-lo. Ele realmente melhora a clareza e vale a pena os poucos caracteres extras. No caso em que você não tem acesso a fazer isso, então um adaptador tem a mesma finalidade de declarar explicitamente como a interface se relaciona com a outra classe.

F # suportes estática tipagem pato, embora com um problema: você tem que usar restrições membros. Os detalhes estão disponíveis neste blog .

Exemplo do blog citados:

let inline speak (a: ^a) =
    let x = (^a : (member speak: unit -> string) (a))
    printfn "It said: %s" x
    let y = (^a : (member talk: unit -> string) (a))
    printfn "Then it said %s" y

type duck() =
    member x.speak() = "quack"
    member x.talk() = "quackity quack"
type dog() =
    member x.speak() = "woof"
    member x.talk() = "arrrr"

let x = new duck()
let y = new dog()
speak x
speak y

A maioria das línguas do apoio da família ML tipos estruturais com inferência e regimes de tipo restritos , que é a terminologia geeky linguagem de design que parece mais provável que você quer dizer com a frase "estático duck- digitação" na pergunta original.

As línguas mais populares para esta família que vêm à mente são: Haskell, Objective Caml, F # e Scala. Aquele que mais se aproxima o seu exemplo, é claro, seria Caml Objetivo. Aqui está uma tradução do seu exemplo:

open Printf

class type iMyInterface = object
  method myMethod: unit
end

class myClass = object
  method myMethod = printf "Hello, world!"
end

let callMyMethod: #iMyInterface -> unit = fun m -> m#myMethod

let myClass = new myClass

callMyMethod myClass

Nota:. Alguns dos nomes que você usou tem que ser mudado para cumprir noção de identificador de caso semântica do OCaml, mas caso contrário, este é uma tradução bastante simples

Além disso, vale a pena notar, nem a anotação de tipo na função callMyMethod nem a definição do tipo de classe iMyInterface é estritamente necessário. Caml objetivo pode inferir tudo no seu exemplo, sem quaisquer declarações de tipo algum.

typescript!

Bem, ok ... Então é um super javascript e talvez não constitui uma "linguagem", mas este tipo de pato-tipagem estática é vital à máquina.

enter descrição da imagem aqui

Boo definitivamente é uma linguagem digitada-duck estática: http://boo.codehaus.org/Duck + Typing

Um trecho:

Boo é uma linguagem de tipagem estática, como Java ou C #. Isso significa que seu boo aplicações irão correr tão rápido quanto aqueles codificados no outro estaticamente digitado idiomas para .NET ou Mono. mas usar uma linguagem de tipagem estática, por vezes, restringe-lo para uma inflexível e detalhado estilo de codificação, com a às vezes declarações de tipo necessária (Como "x como int", mas isso não é devido frequentemente necessário Tipo de boo Inferência) e às vezes necessário Tipo moldes (consulte Tipos de seleção de elenco). boo de suporte para Tipo Inferência e eventualmente genéricos ajudar aqui, mas ...

Às vezes é apropriado para desistir a rede de segurança fornecido pelo estática digitando. Talvez você só quer explorar uma API sem se preocupar muito com assinaturas de método ou talvez você está a criação de código que fala externa componentes, tais como objectos COM. Ou maneira a escolha deve ser o seu não meu.

Junto com os tipos normais como objeto, int, corda ... boo tem um tipo especial chamado de "pato". O termo é inspirada na programação Ruby recurso pato digitação de linguagem ( "Se anda como um pato e grasna como um pato, deve ser um pato ").

Novas versões do movimento C ++ na direção de tipagem pato estática. Você pode algum dia (hoje em dia?) Escrever algo como isto:

auto plus(auto x, auto y){
    return x+y;
}

e que iria deixar de compilar se não há nenhuma chamada de função correspondente para x+y.

Quanto à sua crítica:

Um novo "CallMyMethod" é criada para cada tipo diferente de passar a ele, por isso não é realmente tipo de inferência.

Mas é a inferência de tipos (você pode dizer foo(bar) onde foo é uma função templated), e tem o mesmo efeito, exceto que é mais tempo eficiente e ocupa mais espaço no código compilado.

Caso contrário, você teria que olhar para cima o método durante a execução. Você teria que encontrar um nome, em seguida, verifique se o nome tem um método com os parâmetros corretos.

Ou você teria para armazenar todas as informações sobre as interfaces correspondentes, e olhar para todas as classes que corresponda a uma interface, então, automaticamente adicionar essa interface.

Em qualquer caso, que lhe permite quebrar implicitamente e, acidentalmente, a hierarquia de classes, que é ruim para um novo recurso porque vai contra os hábitos do que os programadores de C # / Java são usados ??para. Com modelos C ++, você já sabe que está em um campo minado (e eles também estão adicionando recursos ( "conceitos") para permitir restrições sobre parâmetros do modelo).

tipos estruturais no Scala faz algo assim.

Veja estaticamente verificado‘Typing Duck’em Scala

projeto

A pré-lançamento para Visual Basic 9 apoio teve para digitação pato estático usando interfaces dinâmicas, mas eles cortaram o recurso * , a fim de navio no tempo.

D ( http://dlang.org ) é uma linguagem compilado estaticamente e fornece pato-digitando via envoltório () e de desenrolamento () ( http://dlang.org/phobos-prerelease/std_typecons.html # .unwrap ).

Crystal é uma linguagem estaticamente pato-digitado. Exemplo :

def add(x, y)
  x + y
end

add(true, false)

A chamada para add causa esse erro de compilação:

Error in foo.cr:6: instantiating 'add(Bool, Bool)'

add(true, false)
^~~

in foo.cr:2: undefined method '+' for Bool

  x + y
    ^

Na versão mais recente da minha linguagem de programação Heron ele suporta algo semelhante através de uma coerção estrutural-subtipagem operador chamado as. Assim em vez de:

MyClass obj = new MyClass();
CallMyMethod(obj);

Você poderia escrever:

MyClass obj = new MyClass();
CallMyMethod(obj as IMyInterface);

Assim como no seu exemplo, neste caso MyClass não tem que implementar explicitamente IMyInterface, mas se ele fez o elenco poderia acontecer implicitamente eo operador as poderia ser omitida.

Eu escrevi um pouco mais sobre a técnica que eu chamo explícita sub-tipagem estrutural em este artigo .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top