2011-08-18 14 views
8

Stavo implementando una libreria di digitazione dinamica per D quando ho riscontrato un problema interessante.Utilizzo della digitazione dinamica in D, un linguaggio tipizzato staticamente

Al momento, sono riuscito a creare una funzione denominata dynamic() che restituisce una versione dinamica di un oggetto.

Ad esempio:

import std.stdio, std.dynamic.core; 

class Foo 
{ 
    string bar(string a) { return a ~ "OMG"; } 
    int opUnary(string s)() if (s == "-") { return 0; } 
} 

void main(string[] argv) 
{ 
    Dynamic d = dynamic(new Foo()); 
    Dynamic result = d.bar("hi"); 
    writeln(result); // Uh-oh 
} 

Il problema che ho incontrato in tutto è il fatto che writeln cercherà di utilizzare fase di compilazione riflessione per capire come trattare result.

Qual è la prima cosa che prova? isInputRange!(typeof(result))

Il problema è che restituisce true! Perché? Perché devo supporre che tutti i membri di cui ha bisogno esistano, a meno che non possa dimostrare il contrario in fase di esecuzione - che è troppo tardi. Quindi il programma tenta di chiamare front, popFront e empty su result, arrestando in modo anomalo il mio programma.

Non riesco a pensare a un modo per risolvere questo problema. Qualcuno ha un'idea?

risposta

1

Cosa c'è di sbagliato con l'utilizzo di std.variant che implementa tutto il necessario per la tipizzazione dinamica (insieme con un po 'di zucchero sintattico)

+1

'std.variant' non supporta i tipi che hanno campi arbitrari. –

+0

@cyber cosa intendi? –

+0

OP vuole creare un oggetto dove 'obj.anything' è valido in fase di compilazione (anche se potrebbe non essere valido in fase di esecuzione). Nulla in 'std.variant 'permette questo, come ho visto. –

1

Potrebbe fornire un sovraccarico per isInputRange? Qualcosa di simile (notare che io non ho guardato l'attuazione di isInputRange):

template isInputRange(T : Dynamic) { 
    enum isInputRange = false; 
} 

Se questo viene fornito dal dynamic.core, penso che questo sovraccarico deve essere scelto prima che lo std uno lib.

+1

Giusto, ma il problema è che questo richiederebbe conoscere in anticipo ogni tipo di prevenzione. Ovviamente, non funziona per chi finisce per usare la mia libreria ... – Mehrdad

+0

Sfortunatamente questo trucco non funziona, std.stdio non può raccogliere la specializzazione. – Lutger

0

In generale, Dynamic deve accettare qualsiasi metodo di ricerca in fase di compilazione, come hai detto. Supponiamo per un momento che si possa impedire al predicato isInputRange di valutare true, ora verrà generato il codice errato quando si tenta di creare una dinamica da un intervallo di input.

Non penso che sia risolvibile, almeno non in modo generale. In questo caso particolare, la soluzione migliore che posso immaginare è che Dynamic fornisce la propria versione di toString, e writeln preferirebbe che fosse la specializzazione inputRange. Credo che writeln non lo faccia al momento, almeno non per le strutture, ma probabilmente dovrebbe.

Un altro compromesso sarebbe quello di non consentire alcuni metodi come popFront nel vincolo opDispatch, invece Dynamic fornirà opIndex o un oggetto membro per accedere a questi casi speciali. Questo potrebbe non essere così male come sembra, perché i casi speciali sono rari e usarli comporterebbe un evidente errore del compilatore.

Penso che il modo migliore per salvare questo tipo di risoluzione dei metodi per Dynamic è di correggere writeln e accettare che Dynamic non funzionerà con tutti i codici basati su modelli.

+0

Il problema di rendere writeln preferisce toString over isInputRange è che ogni classe eredita un metodo toString generico da Object, che restituisce solo il nome della classe. Pertanto, se writeln fosse cambiato, avrebbe dovuto trattare le strutture e le classi in modo diverso. – tgehr

2

Si sta tentando di far funzionare due concetti fondamentalmente diversi, ovvero modelli e digitazione dinamica. I modelli si basano molto sulla tipizzazione statica, isInputRange funziona controllando quali attributi o metodi ha un tipo. Il tuo tipo dinamico viene considerato come dotato di ogni attributo o metodo in fase di compilazione, quindi viene considerato come soddisfacente ogni interfaccia di tipizzazione anatra statica. Pertanto, per fare in modo che Dynamic funzioni in un ambiente tipizzato staticamente, è necessario fornire più informazioni statiche in alcuni punti.

Alcune soluzioni che posso vedere:

  1. forniscono le proprie implementazioni dinamicamente tipizzati per le funzioni molto utilizzati. L'intero problema che si sta verificando è causato dal fatto che si sta tentando di utilizzare funzioni generiche che presuppongono la digitazione statica con tipi dinamici.

  2. rendere esplicitamente dinamico un intervallo di caratteri e curare personalmente la conversione in stringa dei dati sottostanti. (Dovresti comunque avere un metodo toString personalizzato se il problema isInputRange non esiste, altrimenti il ​​risultato sarebbe di nuovo di tipo Dinamico). Questo probabilmente renderebbe writeln (d); lavoro.

  3. forniscono wrapper dinamici che consentono di passare tipi dinamici in varie funzioni basate su modelli. (Quelli mostrano solo un'interfaccia statica e inoltrano tutte le chiamate a Dynamic).

Esempio:

Dynamic d; 
// wrap d to turn it into a compile-time input range (but NOT eg a forward range) 
Dynamic d2=dynamic(map!q{a*2}(dynInputRange(d))); 
// profit 

4. Aggiungi un modello membro a Dynamic, che consente di disabilitare staticamente alcuni nomi di funzioni membro.

Esempio:

static assert(!isForwardRange!(typeof(d.without!"save"))); 
0

Avete guardato in std.variant?

import std.stdio, std.variant; 

class Foo { 
    string Bar(string a) { 
     return a ~ " are Cool!"; 
    } 
} 

void main() { 
    Variant foo = new Foo(); 
    Variant result = foo.peek!Foo.Bar("Variants"); 

    writeln(result); // Variants are Cool! 
} 

http://www.d-programming-language.org/phobos/std_variant.html

Problemi correlati