Использование динамической типизации в D, статически типизированном языке - PullRequest
8 голосов
/ 18 августа 2011

Я реализовывал библиотеку динамической типизации для D, когда натолкнулся на интересную проблему.

Сейчас мне удалось создать функцию с именем dynamic(), которая возвращает динамическую версию объекта.

Например:

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
}

Проблема, с которой я столкнулся, заключается в том, что writeln пытается использовать время компиляции отражение, чтобы понять, какугощение result.

Что первое, что он пробует?isInputRange!(typeof(result))

Проблема в том, что он возвращает true !Зачем?Потому что я должен предположить, что все члены, которые ему нужны, существуют, если только я не могу доказать обратное во время выполнения - что слишком поздно.Поэтому программа пытается вызвать front, popFront и empty на result, что приводит к сбою моей программы.

Я не могу придумать, как это исправить.У кого-нибудь есть идея?

Ответы [ 5 ]

2 голосов
/ 22 августа 2011

Вы пытаетесь совместить две принципиально разные концепции, а именно шаблоны и динамическую типизацию. Шаблоны во многом полагаются на статическую типизацию, isInputRange работает, проверяя, какие атрибуты или методы имеет тип. Ваш динамический тип обрабатывается как имеющий каждый атрибут или метод во время компиляции, поэтому он обрабатывается как удовлетворяющий каждый интерфейс статической типизации утки. Поэтому, чтобы заставить Dynamic работать в статически типизированной среде, вам нужно предоставить больше статической информации в некоторых местах.

Некоторые решения, которые я вижу:

  1. обеспечивает ваши собственные динамически типизированные реализации для интенсивно используемых функций. Вся ваша проблема вызвана тем, что вы пытаетесь использовать универсальные функции, которые предполагают статическую типизацию с динамическими типами.

  2. явно делает динамические диапазоны символов и заботятся о преобразовании в строку базовых данных самостоятельно. (В любом случае вам придется иметь собственный метод toString, если проблема isInputRange не существует, потому что в противном случае ее результат снова будет иметь тип Dynamic). Это вероятно сделало бы writeeln (d); работа.

  3. предоставляют оболочки для динамических функций, которые позволяют передавать динамические типы в различные шаблонные функции. (Они будут просто демонстрировать статический интерфейс и перенаправлять все вызовы в Dynamic).

Например:

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. Добавьте шаблон члена в Dynamic, который позволяет статически отключать некоторые имена функций-членов.

Например:

static assert(!isForwardRange!(typeof(d.without!"save")));
1 голос
/ 18 августа 2011

Не могли бы вы предоставить перегрузку для isInputRange?Примерно так (обратите внимание, что я не смотрел на реализацию isInputRange):

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

Если это предусмотрено вашим dynamic.core, я думаю, что эта перегрузка должна быть выбрана перед std lib.

1 голос
/ 18 августа 2011

что не так с использованием std.variant, который реализует все, что вам нужно для динамической типизации (вместе с небольшим количеством синтаксического сахара)

0 голосов
/ 24 октября 2011

Вы смотрели в 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 / фобос / std_variant.html

0 голосов
/ 22 августа 2011

В общем случае Dynamic должен принимать любой метод поиска во время компиляции, как вы сказали.Предположим на мгновение, что вы можете запретить предикату isInputRange вычислять значение true, теперь неправильный код будет сгенерирован при попытке создать Dynamic из входного диапазона.

Я не думаю, что это поправимо, по крайней мере, не в общем смысле.В этом конкретном случае лучшее решение, которое я могу придумать, состоит в том, что Dynamic предоставляет свою собственную версию toString, и writeln предпочел бы ее над специализацией inputRange.Я считаю, что writeln не делает этого в данный момент, по крайней мере, не для структур, но, вероятно, должно.

Другим компромиссом было бы запретить несколько методов, таких как popFront, в ограничении opDispatch, вместо этого Dynamic предоставил бы opIndex или объект-член для доступа к этим особым случаям.Это может быть не так плохо, как кажется, потому что особые случаи редки, и их использование приведет к очевидной ошибке компиляции.

Я думаю, что лучший способ спасти такое разрешение методов для Dynamic - этоисправьте writeln и примите, что Dynamic не будет работать со всем шаблонным кодом.

...