I was implementing a dynamic typing library for D when I ran across an interesting problem.
Right now, I've succeeded in making a function called dynamic()
which returns a dynamic version of an object.
For example:
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
}
The problem I've run across is the fact that writeln
tries to use compile-time reflection to figure out how to treat result
.
What's the first thing it tries? isInputRange!(typeof(result))
The trouble is, it returns true! Why? Because I have to assume that all members which it needs exist, unless I can prove otherwise at run time -- which is too late. So the program tries to call front
, popFront
, and empty
on result
, crashing my program.
I can't think of a way to fix this. Does anyone have an idea?
A language is dynamically typed if the type is associated with run-time values, and not named variables/fields/etc. This means that you as a programmer can write a little quicker because you do not have to specify types every time (unless using a statically-typed language with type inference).
First, dynamically-typed languages perform type checking at runtime, while statically typed languages perform type checking at compile time.
Statically typed languages perform type checking at compile-time, while dynamically-typed languages perform type checking at run-time. Statically-typed languages require you to declare the data types of your variables before you use them, while dynamically-typed languages do not.
Conversely, in dynamically typed languages, type checking takes place at runtime or execution time. This means that variables are checked against types only when the program is executing. Some examples of programming languages that belong to this category are Python, JavaScript, Lisp, PHP, Ruby, Perl, Lua, and Tcl.
You are trying to make two fundamentally different concepts work together, namely templates and dynamic typing. Templates rely very much on static typing, isInputRange works by checking which attributes or methods a type has. Your dynamic type is treated as having every attribute or method at compile time, ergo it is treated as fulfilling every static duck-typing interface. Therefore, to make Dynamic work in a statically typed environment, you have to provide more static information at some places.
Some solutions I can see:
provide your own dynamically typed implementations for heavily used functions. The whole problem you are having is caused by the fact that you are trying to use generic functions that assume static typing with dynamic types.
explicitly make dynamic a range of char, and care for the conversion to string of the underlying data yourself. (You'd have to have a custom toString method anyways if the isInputRange issue would not exist, because otherwise its result would again be of Dynamic type). This would probably make writeln(d); work.
provide wrappers for dynamic that allow you to pass dynamic types into various templated functions. (Those would just exhibit a static interface and forward all calls to Dynamic).
Eg:
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 . Add a member template to Dynamic, which allows to statically disable some member function names.
Eg:
static assert(!isForwardRange!(typeof(d.without!"save")));
what is wrong with using std.variant
which implements all you need for dynamic typing (along with quite a bit of syntactic sugar)
Could you provide an overload for isInputRange? Something like this (note that I haven't looked at the implementation of isInputRange):
template isInputRange(T : Dynamic) {
enum isInputRange = false;
}
If this is provided by your dynamic.core, I think this overload should be chosen before the std lib one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With