On Saturday, 29 June 2013 at 19:18:13 UTC, Ary Borenszweig wrote:
On 6/27/13 9:34 PM, JS wrote:
Would it be possible for a language(specifically d) to have
the ability
to automatically type a variable by looking at its use cases
without
adding too much complexity? It seems to me that most compilers
already
can infer type mismatchs which would allow them to handle
stuff like:
main()
{
auto x;
auto y;
x = 3; // x is an int, same as auto x = 3;
y = f(); // y is the same type as what f() returns
x = 3.9; // x is really a float, no mismatch with previous
type(int)
}
in this case x and y's type is inferred from future use. The
compiler
essentially just lazily infers the variable type. Obviously
ambiguity
will generate an error.
What you are asking is essentially what Crystal does for all
variables (and types):
https://github.com/manastech/crystal/wiki/Introduction#type-inference
Your example would be written like this:
x = 3
y = f()
x = 3.9
But since Crystal transforms your code to SSA
(http://en.wikipedia.org/wiki/Static_single_assignment_form)
you actually have *two* "x" variables in your code. The first
one is of type Int32, the second of type Float64. The above
solves the problem mentioned by Steven Schveighoffer, where you
didn't know what overloaded version you was calling:
x = 3
f(x) # always calls f(Int32), because at run-time
# x will always be an Int32 at this point
x = 3.9
But to have this in a language you need some things:
1. Don't have a different syntax for declaring and updating
variables
2. Transform your code to SSA
(maybe more?)
So this is not possible in D right now, and I don't think it
will ever be because it requires a huge change to the whole
language.
This is not what I am talking about and it seems quite dangerous
to have one variable name masquerade as multiple variables.
I am simply talking about having the compiler enlarge the type if
needed. (this is mainly for built in types since the type
hierarchy is explicitly known)
e.g.,
auto x = 3;
x = 3.0; // invalid, but there is really no reason
It's obvious that we wanting x to be a floating point... why not
expand it to one at compile time? Worse thing in general is a
performance hit.
One can argue, and it has been already stated, that one doesn't
know which overloaded function is called. This is true, but if
one uses auto(or rather a more appropriate keyword), then the
programmer knows that the largest type will be used. In general,
it will not be a problem at all because the programmer will not
intentionally treat a variable as a multi-type(which seems to be
what crystal is doing).
What I am talking about allows us to do a few things easily:
auto x;
...
x = 3.0; // x's type is set to a double if we do not assign x a
larger x compatible with double.
auto x;
...
x = 3; // x is set to an int type, we don't have to immediately
assign to x. this is not very useful though.
more importantly, the we can have the compiler infer the type
when we mix subtypes:
auto x; // x is a string
x = 3; // x is a string
x = 3.0; // x is a string
x = "" // x is a string
but if we remove the last line we end up with
auto x; // x is a double
x = 3; // x is a double
x = 3.0; // x is a double
Which, the importance is that the compiler is choosing the most
appropriate storage for us. x is not a multi variable like
crystal nor a variant. It is simply an auto variable that looks
at the entire scope rather than just its immediate assignment.
If one prefers,
{
autoscope x;
// x is defined as the largest type used
}
One problem is user defined types. Do we allow inheritance to be
used:
{
autoscope x;
x = new A;
x = new B;
} // x is of type B if B inherits A, else error
this would be the same as
auto x = (B)(new A);