Come forzare chiamare solo metodi della superclasse, nonostante che sia stato uno scostamento (in OCaml)

StackOverflow https://stackoverflow.com/questions/4829597

Domanda

Per essere onesti, non so molto circa il sistema oggetto di OCaml. Il seguente frammento di codice illustra il mio problema:

class foo =
  object (o)

    method foo1 y =
      print_endline "foo1";
      o#foo2 (y - 1)

    method foo2 y =
      print_endline "foo2";
      if y > 0 then o#foo2 y else print_endline "end"
  end

class bar =
  object (o : 'self_type)
    inherit foo as super

    method foo2 y =
    print_endline "bar2";
    if y > 0 then super#foo1 y else print_endline "endbar"

  end

let _ = (new bar)#foo2 3

Quando eseguito, il frammento produce il seguente output:

bar2
foo1
bar2
foo1
bar2
endbar

, dimostrando che il metodo della superclasse foo1 (chiamata via eccellente # foo1) esegue il metodo foo2 sovresposta dalla sottoclasse. Vorrei invece aspettato a chiamare il metodo foo2 dalla superclasse, come viene chiamato tramite eccellente.

E 'possibile ottenere questo comportamento, vale a dire avere una chiamata di metodo della superclasse soli altri metodi della superclasse anche se sono sovrascritti in una sottoclasse?

È stato utile?

Soluzione

Non sono sicuro al 100% su questo, ma sono abbastanza sicuro che non si può. In OCaml eredità e subtyping sono due concetti diversi. Una classe può essere un sottotipo di un altro tipo, senza eredità. Tutto eredità fa è tirare nei metodi della classe ereditata.

polimorfismo avviene tramite digitazione strutturale, quindi la chiamata al foo2 chiama il metodo in bar perché bar ha implementato foo2 e non perché eredita bar da foo (come apposto a dire, C ++, dove bar#foo2 è chiamato a causa di una tabella di funzione virtuale guardare in alto).

Detto questo, OCaml non vi fornirà un modo per distinguere tra i metodi sostituiti e metodi ereditati utilizzando la sintassi inherit...as.... In bar dal vostro esempio, o#foo1 e super#foo1 sono lo stesso metodo (poiché bar non implementa foo1) che o#foo2 e super#foo2 sono metodi differenti. Nonostante questo, non credo che ci sia in ogni caso per la classe ereditata per sapere che è stato ereditato e distinguere tra IT di metodi ed i metodi sostituiti. Ci potrebbe essere qualche sintassi per questo, ma dubito fortemente che a causa del fatto che ereditarietà e polimorfismo sono concetti indipendenti.

Altri suggerimenti

No non lo è. Questo è "tardiva", un'idea di base di OO, non specifiche per OCaml.

Non so quello che stai cercando di fare, ma la programmazione orientata agli oggetti, non è forse gli strumenti giusti, o almeno non utilizzato in questo modo. Se volete imparare OCaml, probabilmente si dovrebbe concentrarsi sulle parti non OO, che è abbastanza interessante per cominciare.

Come sottolinea Gasche, questo è il comportamento previsto e standard per i linguaggi OO.

La chiamata super#foo1, dal momento che bar non sovrascrive foo1, è esattamente equivalente a o#foo1. Il costrutto super esiste solo essere in grado di chiamare il metodo foo2 di foo metodi in bar (altrimenti non c'è modo fare riferimento a tale metodo). In foo1 come richiesto dal bar#foo2, o è in realtà un bar, non un foo, quindi richiamare il metodo foo2 invoca il metodo bar foo2.

Direi che se si vuole hardcode che il comportamento, è meglio non utilizzare la programmazione orientata agli oggetti. Semplicemente attuarla come funzioni chiamare altre funzioni.

( "quel comportamento", come intesa da me: se chiamate foo2 dall'interno del codice che è stato chiamato come super#foo1, quindi esattamente la foo2 dall'attuazione della superclasse dovrebbe essere chiamato, non dai più "specifici" implementazioni da sottoclassi)

E 'il modo più semplice e più pulito e più chiaro per procedere:. Funzioni del programma che fare quello che vuoi

In alternativa si dovrebbe spiegare a se stessi ea noi: Perché avete bisogno OOP? La ragione per questo non è dato nel testo della domanda. Perché fare foo1 e metodi foo2 piuttosto che funzioni indipendenti? (A parte foo1 e foo2, è possibile che alcuni oggetti e classi e metodi nel vostro programma, se del caso).

Chiedendosi se questa domanda viene da confronto ad altri lnaguages ??

Se si conosce altro linguaggio OO, che è strano che si desidera "che il comportamento" da OOP: non è il comportamento previsto, per esempio, Java o C ++, perché impiegano il concetto di una tabella di metodi virtuali che è associato con ogni oggetto a run-time, in modo da quando si chiama un metodo nel vostro programma, esso viene inviato in fase di esecuzione per l'attuazione di tale metodo in realtà associato con l'oggetto. Così, in breve: ogni volta che si utilizza l'espressione metodo-chiamata nel programma, ti impegni a questo principio di trovare l'implementazione del metodo ( "associazione tardiva") , come fuori puntato da Gasche. Anche se ancora cf. le differenze tra OCaml e lingue implementate con un tavolo metodi virtuali sottolineato da Niki Yoshiuchi.

formalizzazione di tutti la discussione dei comportamenti disponibili e ricercati

Anche se ciò che si desidera potrebbe non essere il comportamento previsto e disponibile in molti linguaggi OO popolari, è immaginabile e potrebbe essere implementabile in alcuni sistemi specifici OOP, se si ha accesso alle parti interne di implementazione OOP.

Say, se in qualche realizzazione, super è una struttura che tiene la tavola metodi della superclasse (di fallback a quando si risolve un invito metodo per l'oggetto corrente), ed i metodi sono funzioni che devono ricevere l'oggetto (tabella metodi ) come il primo arg, quindi di eseguire ciò che si vuole, si potrebbe scrivere super.foo1(super, y).

(io in realtà chiedo se ci sono implementazioni OOP i cui interni sono esposti al programmatore e che consentono di fare una tale chiamata.)

considerando normale comportamento UPU sarebbe espressa in questo sistema this.foo1(this, y) (dove this è la tabella metodi per l'oggetto corrente.)

La chiamata super#foo1 y OCaml o un super.foo1(y); Java si traduce in questo "mio" sistema super.foo1(this, y). (Anche se ancora cfr le differenze evidenziate da Niki Yoshiuchi tra OCaml e linguaggi come Java realizzato con un tavolo metodi virtuali.)

Si vede le differenze tra i 3 casi.

Appendice. Guardando per le lingue che funziona in questo modo

Hmm, PHP potrebbe essere un linguaggio in cui tale comportamento sarebbe stato possibile, ma:

  • solo sul "livello di classe" programmazione (metodi statici), non oggetto di livello;
  • solo quando si hardcode qualche strana "binding statico in ritardo " alle chiamate di funzione:

#!/usr/bin/php
<?php
class Foo {
  public static function foo1($y) {
    echo "foo1\n";
    static::foo2($y-1);
  }

  public static function foo2($y) {
    echo "foo2\n";
    if ($y > 0)
      static::foo2($y);
    else
      echo "end\n";
  }
  }

class Bar extends Foo {
  public static function foo2($y) {
    echo "bar2\n";
    if ($y > 0)
      Foo::foo1($y);
    else
      echo "endbar\n";
  }
}

class Model extends Foo {
  public static function foo2($y) {
    echo "model2\n";
    if ($y > 0)
      static::foo1($y);
    else
      echo "endmodel\n";
  }
}

Model::foo2(3);

Bar::foo2(3);
?>

I si comporta modello in un certo senso come OO standard di oggetti con metodi virtuali, e bar come si voleva :

$ ./test-force-super-binding.php | head -20
model2
foo1
model2
foo1
model2
foo1
model2
endmodel
bar2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$ 

(BTW, utilizzando parent:: invece di Foo:: non otterrebbe noi al vostro comportamento voluto.)

Non capisco il prupose delle specifiche vincolanti del PHP folle come static::, che sono di qualche effetto solo per i metodi statici (cioè, programmazione classe-livello).

Un C ++ analoga aperta esempio non dà un comportamento livello oggetto OO di default:


#include<iostream>

class Foo {
protected:
  static void foo1(int y) {
    std::cout << "foo1" << std::endl;
    foo2(y-1);
  }

public:
  static void foo2(int y) {
    std::cout << "foo2" << std::endl;
    if (y > 0)
      foo2(y);
    else
      std::cout << "end" << std::endl;
  }

};

class Bar: public Foo {
public:
  static void foo2(int y) {
    std::cout << "bar2" << std::endl;
    if (y > 0)
      foo1(y);
    else
      std::cout << "endbar" << std::endl;
  }
};

int main() {
  Bar::foo2(3);
  return 0;
}

- si dà il vostro comportamento desiderato:

$ ./a.out | head -10
bar2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$ 

anche senza alcuna qualificazione speciale alla chiamata di funzione nel codice per Bar::foo2(), quindi non interessante per noi.

Che dire di metodi statici di Java? .. (cosa differiscono da C ++ e ci danno un virtual-metodo-come la risoluzione della funzione-chiamate di default?)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top