www.digitalmars.com         C & C++   DMDScript  

D - inferred types

reply Kimberley Burchett <kimbly at kimbly.com> <Kimberley_member pathlink.com> writes:
A small, simple feature suggestion.  The "var" keyword could introduce a
variable with an inferred type:

void foo(int x) {
var y = x + 1;
printf("y is %d\n", y);
}

This feature is especially useful in situations where you don't *know* the type
of an expression.  For example, if the above example used a template so that x
has some unspecified type T, and the + operator for T were overloaded, then
there would be no way to know the type of T+int.  One could of course just
assume that it would be the same type as x itself, but that doesn't scale to
letting y store the result of arbitrary expressions.

Exploring the orthogonality of the feature... The "var" keyword could also be
allowed for function arguments, where it could implicitly define a function
template.  Also, for functions with consistent return types, you could allow it
for the return value (again, this would be important for situations where you
don't know the result type of an overloaded operator).  However, it would look a
bit odd if used as a return type:

var foo(int x) {
return x+1;
}

It kind of looks like foo should be a variable, not a function.  So you might
want to rename the keyword.  One choice would be to use "T" instead of "var",
but then writing templates would be a bit more annoying because you'd have to
come up with a name for your parameterized types.

Even if this feature is not adopted, D should probably still have *some* way of
dealing with situations where you don't know the type of an expression.  I
suppose you could allow use of a type() property wherever a type is expected:

(x+1).type() foo(SomeType x) {
return x+1;
}

But that strikes me as a lot uglier than using "var" or "T".

Kimberley Burchett
Endeca, Inc
Jan 15 2003
next sibling parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
"Kimberley Burchett" <kimbly at kimbly.comKimberley_member pathlink.com>
wrote in message news:b03d3k$2m8r$1 digitaldaemon.com...
 A small, simple feature suggestion.  The "var" keyword could introduce a
 variable with an inferred type:

 void foo(int x) {
 var y = x + 1;
 printf("y is %d\n", y);
 }
YES!!! for (var iter = container.begin(); iter != container.end(); ++iter) { *iter = 0; }
 This feature is especially useful in situations where you don't *know* the
type
 of an expression.  For example, if the above example used a template so
that x
 has some unspecified type T, and the + operator for T were overloaded,
then
 there would be no way to know the type of T+int.  One could of course just
 assume that it would be the same type as x itself, but that doesn't scale
to
 letting y store the result of arbitrary expressions.
Or if you don't want to type out a really lengthy type, or make a typedef for it. See C++ iterators. for (std::map<std::basic_string<char>, std::less<std::basic_string<char> >
::const_iterator iter = container.begin(); iter != container.end(); ++iter)
{ foo(*iter); }
 Exploring the orthogonality of the feature... The "var" keyword could also
be
 allowed for function arguments, where it could implicitly define a
function
 template.
Interesting... you mean: x.type() add(var x, var y) { return x + y; } int u = add(2, 4); float n = add(0.5f, 1.0f); double j = add(2.5, 3.0); Sounds nice; it'd be even better if you can constrain the types to be derived from some interface x.type() add(var x : addable, var y : addable) { return x + y; }
 Also, for functions with consistent return types, you could allow it
 for the return value (again, this would be important for situations where
you
 don't know the result type of an overloaded operator).  However, it would
look a
 bit odd if used as a return type:

 var foo(int x) {
 return x+1;
 }

 It kind of looks like foo should be a variable, not a function.  So you
might
 want to rename the keyword.  One choice would be to use "T" instead of
"var",
 but then writing templates would be a bit more annoying because you'd have
to
 come up with a name for your parameterized types.

 Even if this feature is not adopted, D should probably still have *some*
way of
 dealing with situations where you don't know the type of an expression.  I
 suppose you could allow use of a type() property wherever a type is
expected:
 (x+1).type() foo(SomeType x) {
 return x+1;
 }

 But that strikes me as a lot uglier than using "var" or "T".
Yes. For one, you have to build the expression twice, once to get its type so you can declare the variable, and again for the actual value. for (container.begin().type() iter = container.begin(); iter != container.end(); ++iter) { *iter = 0; }
 Kimberley Burchett
 Endeca, Inc
Jan 15 2003
parent reply Ilya Minkov <midiclub 8ung.at> writes:
Sean L. Palmer wrote:
 "Kimberley Burchett" <kimbly at kimbly.comKimberley_member pathlink.com>
 wrote in message news:b03d3k$2m8r$1 digitaldaemon.com...
 
A small, simple feature suggestion.  The "var" keyword could introduce a
NOT SIMPLE i guess!
variable with an inferred type:

void foo(int x) {
var y = x + 1;
printf("y is %d\n", y);
}
YES!!!
Damn. It doesn't seem reliable to me. In Caml types are only inferred, but it has to do with a number of design limitations: - there are different sets of operators for all types of data. EG: int + int, float +. float, bign +/ bign!!! If there's no such thing, you get error-prone situations. Well, that'd be no problem in Delphi, but in C derivates it is, because integer division and FP devision are the same operator here, but have a different meaning! - there are only two types of data structures: containing pointers and integers only, and containing no pointers. Each float is a memory block/sctucture itself, except for designated array types, which can only be processed with special (C-external or VM-internal) functions. Both floats and arrays belong to no-pointer-block types. - all integers are the size of pointers -1 bit (eg 31 bit), because they are mangled so that the GC can differ pointer from integer. - either a function handles a pointer-sized type and would work with any of them, or it works with numeric types and can be identified by the operators. - "generic" functions working with pointers and integers never clean up and never change them, they can only copy them, leaving a ton of work to the mega-efficient GC.
This feature is especially useful in situations where you don't *know* the type
of an expression.  For example, if the above example used a template so that x
has some unspecified type T, and the + operator for T were overloaded, then
there would be no way to know the type of T+int.  One could of course just
assume that it would be the same type as x itself, but that doesn't scale to
letting y store the result of arbitrary expressions.
OUCH! safer: operator+ (T, int).type if one really wants to know. I agree there should be some mechanism, but it must work statically, and thus be semantically identical to this one. And what happenes if you take unspecified type of unspecified type of still not specified type? A function can not be compiled without a type. Thus it would turn into something like a macro or a template. Or into C++ overloaded functions. Either you bloat everything, or you have to assign all that funcs names. And here we go again.
 Or if you don't want to type out a really lengthy type, or make a typedef
 for it.  See C++ iterators.
:/ why not create an iterator object and then: Iterator.Load("blah"); while (Iterator.While) { // action }
Jan 15 2003
parent reply Kimberley Burchett <kimbly at kimbly.com> <Kimberley_member pathlink.com> writes:
In article <b04bav$6fd$1 digitaldaemon.com>, Ilya Minkov says...
Damn. It doesn't seem reliable to me. In Caml types are only inferred, 
but it has to do with a number of design limitations:
  - there are different sets of operators for all types of data. EG:
int + int, float +. float, bign +/ bign!!! If there's no such thing, you 
get error-prone situations. Well, that'd be no problem in Delphi, but in 
C derivates it is, because integer division and FP devision are the same 
operator here, but have a different meaning!
I should clarify. I was assuming that the right-hand-side was fully typed. I'm not suggesting full Hindley-Milner-style type inference here. No unification is necessary. I probably shouldn't have used the word "infer" -- I meant something much simpler. The D compiler already has to compute the type of all expressions anyway, in order to know whether they're a compile error, or whether they require an implicit cast, etc. So this is just a shorthand to say that that type of the rhs should be used for the new variable. It would be perfectly reasonable to, say, prevent the use of a var return type for recursive (or mutually recursive) functions. Otherwise you'd have to solve for the type, instead of simply knowing it. However the original motivation for the feature didn't even involve return types -- it was just for local variables, which are syntactically prevented from having recursive definitions anyway.
  - all integers are the size of pointers -1 bit (eg 31 bit), because 
they are mangled so that the GC can differ pointer from integer.
My proposal has nothing to do with tagged values.
  - either a function handles a pointer-sized type and would work with 
any of them, or it works with numeric types and can be identified by the 
operators.
You're thinking I suggested type inference for function arguments. But I didn't -- I suggested that if used as a parameter, then the "var" keyword could actually introduce a *template*. And templates in D apparently have to be explicitly instantiated. So this objection is not relevant. I personally don't even know if I like the implicit template idea -- I was just exploring it for orthogonality reasons.
  - "generic" functions working with pointers and integers never clean 
up and never change them, they can only copy them, leaving a ton of work 
to the mega-efficient GC.
You've jumped from the static type system into the runtime memory model, and implied that the first complicates the second. But all that I'm proposing is a syntactic shorthand for something that can be statically computed. If the compiler decides to replace a particular use of the "var" keyword with the type "float", then I could just as easily have typed "float" in the first place. Therefore there are no runtime implications beyond what the language already allows.
OUCH! safer:
operator+ (T, int).type
if one really wants to know. I agree there should be some mechanism, but 
it must work statically, and thus be semantically identical to this one.
This is the same as what I suggested with the .type() property. But I think it's ugly. Perhaps in my original post I should have emphasized the word "*consistent* return types". What I meant to imply by that was that return values could only be left omitted if the function returned a value whose type was completely determinable from the type of the arguments, and which if it has multiple return points, all return *exactly* the same static type.
And what happenes if you take unspecified type of unspecified type of 
still not specified type?
The compiler builds a DAG, and if it discovers a cycle, then you get a compile error.
A function can not be compiled without a type. Thus it would turn into 
something like a macro or a template.
Exactly! :) I was proposing that if the type of an argument was omitted, then you get a template. And if the type of the return value is omitted, then it must be deducible from the types of the arguments.
:/
why not create an iterator object and then:

Iterator.Load("blah");
while (Iterator.While) {
   // action
}
Because then you have to have a single iterator class that's capable of iterating over everything. Otherwise you'd have to use a more specific type than just "Iterator".
Jan 15 2003
parent Ilya Minkov <midiclub 8ung.at> writes:
Kimberley Burchett  wrote:
 In article <b04bav$6fd$1 digitaldaemon.com>, Ilya Minkov says...
=20
Damn. It doesn't seem reliable to me. In Caml types are only inferred, =
but it has to do with a number of design limitations:
 - there are different sets of operators for all types of data. EG:
int + int, float +. float, bign +/ bign!!! If there's no such thing, yo=
u=20
get error-prone situations. Well, that'd be no problem in Delphi, but i=
n=20
C derivates it is, because integer division and FP devision are the sam=
e=20
operator here, but have a different meaning!
=20 =20 I should clarify. I was assuming that the right-hand-side was fully typed. I'm not suggesting full Hindley-Milner-style type inference here. No unification is necessary. I probably shouldn't have used the word "infer" -- I meant something much simpler. =20 The D compiler already has to compute the type of all expressions anyway, in order to know whether they're a compile error, or whether they require an implicit cast, etc. So this is just a shorthand to say that that type of the rhs should be used for the new variable.
True. OK. That settles most of it. It is a minor change then.
 However the original motivation for the feature didn't even involve
 return types -- it was just for local variables, which are syntacticall=
y
 prevented from having recursive definitions anyway.
=20
=20
 - all integers are the size of pointers -1 bit (eg 31 bit), because=20
they are mangled so that the GC can differ pointer from integer.
=20 =20 My proposal has nothing to do with tagged values.
:/ It just explained how come that "generic" type is allowed in Caml. This=20 "generic" is simply either an integer, or a pointer to any kind of=20 object, so that so far no operations except for equality comparison and=20 copying are done on them, it can be done. But i don't think there should = be such a thing in D.
=20
 If the compiler decides to replace a particular use of the "var"
 keyword with the type "float", then I could just as easily have
 typed "float" in the first place.  Therefore there are no runtime
 implications beyond what the language already allows.
=20
OK. Set.
=20
OUCH! safer:
operator+ (T, int).type
if one really wants to know. I agree there should be some mechanism, bu=
t=20
it must work statically, and thus be semantically identical to this one=
=2E
=20
=20
 This is the same as what I suggested with the .type() property.  But
 I think it's ugly.  Perhaps in my original post I should have emphasize=
d
 the word "*consistent* return types".  What I meant to imply by that=20
 was that return values could only be left omitted if the function
 returned a value whose type was completely determinable from the type
 of the arguments, and which if it has multiple return points, all
 return *exactly* the same static type.
A function can not be compiled without a type. Thus it would turn into =
something like a macro or a template.
=20 =20 Exactly! :) I was proposing that if the type of an argument was omitted, then you get a template. And if the type of the return value is omitted, then it must be deducible from the types of the arguments. =20
OK. A template then. I'm sorry, I guess a lot of misunderstanding comes=20 from my mistake, by which i was answering a reply to your message, not=20 your original one. In the satement: var name expression; expression is evaluated and a variable 'name' is created with the type=20 of expression, if it has a type. As if there stood typeof(expression) name; and typeof() would exist. :) It would be semantically the same as in my=20 earlier post, but much prettier. But then again: this may only be=20 allowed within explicit template instantion. The problem of '/' is rather of general nature. It is to my opinion=20 always undesired if someone writes '7/4' and gets '1', these may be some = variables, the type of which may be hidden behind something else... To=20 my opinion '/' has to *always* return an "extended" type. There has to=20 be another operator for integer devision. It's just like it was done with concatenation. Integer division is of a=20 different nature than FP-division, while other operations are of the=20 same and give the same results. Maybe take '\' for integer division,=20 since it's not used for line splicing like in C? I'd say it would be generally good if it was possible to use any=20 function, which takes two operands, with infix notation. Eg: first $chewTwo second instead of: chewTwo(first, second) Well, it has some problems. First, with infix notation some measure=20 needs to be taken to identify the function both visually and maybe also=20 enclosing between two symbols ( {chewTwo}, /chewTwo/, \chewTwo\ ), or=20 maybe by a postfix or even parenthesis: first chewTwo() second But if prefix or enclosing are chosen, it could also clarify the syntax=20 in some situations when used with one-parameter function, like: $chewOne input instead of: chewOne (input) which is though silly when standalone, may be of great use in=20 expressions already choking of parenthesis. Like in the old C=20 "(((((lisp)))))" joke. Another problem with infix notation is that the order of precedence is=20 not specified. Either it has to be explicitly stated in function=20 declarations, or all the functions would get the highest possible=20 precedence, and then... it would possibly save only one level of=20 parenthesis or not much more than that, which is though a lot in some cas= es.
=20
:/
why not create an iterator object and then:

Iterator.Load("blah");
while (Iterator.While) {
  // action
}
=20 =20 Because then you have to have a single iterator class that's capable of iterating over everything. Otherwise you'd have to use a more specific type than just "Iterator".
Well, i have used a similar thing once. I just put such an iterator=20 functionality into a class, to iterate over data in that particular=20 class. Probably because of having no better solution. Though it was OK=20 for the situation, it is not generally usable, like over any kind of=20 everything.
=20
=20
Jan 17 2003
prev sibling parent reply Daniel Yokomiso <Daniel_member pathlink.com> writes:
In article <b03d3k$2m8r$1 digitaldaemon.com>, Kimberley Burchett <kimbly at
kimbly.com> says...
A small, simple feature suggestion.  The "var" keyword could introduce a
variable with an inferred type:

void foo(int x) {
var y = x + 1;
printf("y is %d\n", y);
}

This feature is especially useful in situations where you don't *know* the type
of an expression.  For example, if the above example used a template so that x
has some unspecified type T, and the + operator for T were overloaded, then
there would be no way to know the type of T+int.  One could of course just
assume that it would be the same type as x itself, but that doesn't scale to
letting y store the result of arbitrary expressions.

Exploring the orthogonality of the feature... The "var" keyword could also be
allowed for function arguments, where it could implicitly define a function
template.  Also, for functions with consistent return types, you could allow it
for the return value (again, this would be important for situations where you
don't know the result type of an overloaded operator).  However, it would look a
bit odd if used as a return type:

var foo(int x) {
return x+1;
}

It kind of looks like foo should be a variable, not a function.  So you might
want to rename the keyword.  One choice would be to use "T" instead of "var",
but then writing templates would be a bit more annoying because you'd have to
come up with a name for your parameterized types.

Even if this feature is not adopted, D should probably still have *some* way of
dealing with situations where you don't know the type of an expression.  I
suppose you could allow use of a type() property wherever a type is expected:

(x+1).type() foo(SomeType x) {
return x+1;
}

But that strikes me as a lot uglier than using "var" or "T".

Kimberley Burchett
Endeca, Inc
Hi, The first kind of var usage seems nice, but in practice I think it can lead to some obscure pieces of code. In the middle of a large method how are you going to interpret this: var foo = bar.testIt(baz, fred, 1, 1.9, "\"); With method overloading in D we need to verify the types of baz and fred so we can discover which version is used. If baz and fred are also var, it can be somewhat hard to understand what's going on. Some weeks ago a programming pissing contest was going on comp.arch and someone said var is no longer than int. I agree that it's true that var is smaller than almost anything else, but I don't think a new keyword is needed just for this half-baked type-inference system. Sather 1.2 provides a ::= assignment that declare lvalue with type and value of rvalue. In Sather 1.3 they are warning against this usage, because it can lead to maintanance problems. But Sather has saner type names than C++, and builtin iterators, so they don't have the std::ListIterator<std::Set<String>> problem ;-) The second usage is similar to current template mechanism, only terser. But this is a problem of template verbosity. IMO it's better to make a simpler template syntax than add another concept to to the same job. Just for the records, I like type system where inference is possible (e.g.: ML or Haskell), but without unification we must always restrict inference to some parts of the problem. Best regards, Daniel Yokomiso.
Jan 16 2003
next sibling parent reply Kimberley Burchett <kimbly at kimbly.com> <Kimberley_member pathlink.com> writes:
The first kind of var usage seems nice, but in practice I think it can lead to
some obscure pieces of code. In the middle of a large method how are you going
to interpret this:

var foo = bar.testIt(baz, fred, 1, 1.9, "\");

With method overloading in D we need to verify the types of baz and fred so we
can discover which version is used. If baz and fred are also var, it can be
somewhat hard to understand what's going on.
I agree that the feature can be used in ways that make code more opaque. But then, so can pointers, templates, operator overloading, unions, exceptions, and many more! :) However I still think something like it is necessary, otherwise templates will be hampered by the type system. I'd like to point out that this: var foo = bar.testIt(baz, fred, 1, 1.9, "\"); print(foo); is completely equivalent to this: print(bar.testIt(baz, fred, 1, 1.9, "\")); However, by using the variable declaration you can avoid order of execution problems (e.g. if there were code between the assignment of foo and the call to print() that would change the return value of bar.testIt). Also, the variable declaration lets you reuse the value more than once without having to call bar.testIt() again. I've never heard anyone claim that you shouldn't be able to compose expressions because it's not clear what the type is of the intermediate values. So why is it a problem here?
Sather 1.2 provides a ::= assignment that declare lvalue with type and 
value of rvalue.  In Sather 1.3 they are warning against this usage, 
because it can lead to maintanance problems.
That's interesting. I didn't know about that feature in Sather. It's also interesting that they're now deprecating it. However I somehow doubt that they're deprecating it just because somebody managed to use it to botch up their code.
IMO it's better to make a simpler template
syntax than add another concept to to the same job.
I would tend to agree. I don't think I like it for function args.
Jan 16 2003
next sibling parent Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Kimberley Burchett wrote:
 That's interesting.  I didn't know about that feature in Sather.  It's
 also interesting that they're now deprecating it.  However I somehow
 doubt that they're deprecating it just because somebody managed to use
 it to botch up their code.
That's nonsense. It is not deprecated at all. One maintainer didn't like it (just like some people have objections about the feature on this list) and since he was the only one really investing time into Sather development, nobody really was in the position to speak up and argue against it. It was a decision of coding style by one person, and his style was mostly guided by high philosophical opinions rather than by real practicability. Ciao, Nobbi
Jan 17 2003
prev sibling parent "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
Hi,

    Comments embedded.

"Kimberley Burchett" <kimbly at kimbly.comKimberley_member pathlink.com>
escreveu na mensagem news:b07aek$1tv0$1 digitaldaemon.com...
[snip]

 I agree that the feature can be used in ways that make code more opaque.
 But then, so can pointers, templates, operator overloading, unions,
 exceptions, and many more! :)  However I still think something like it
 is necessary, otherwise templates will be hampered by the type system.
You can program Fortran in any language ;-)
 I'd like to point out that this:

 var foo = bar.testIt(baz, fred, 1, 1.9, "\");
 print(foo);

 is completely equivalent to this:

 print(bar.testIt(baz, fred, 1, 1.9, "\"));

 However, by using the variable declaration you can avoid order of
 execution problems (e.g. if there were code between the assignment of
 foo and the call to print() that would change the return value of
 bar.testIt).  Also, the variable declaration lets you reuse the value
 more than once without having to call bar.testIt() again.

 I've never heard anyone claim that you shouldn't be able to compose
 expressions because it's not clear what the type is of the intermediate
 values.  So why is it a problem here?
No real problem I was just trying to make a point. Which point I leave as an exercise to the reader ;-)
Sather 1.2 provides a ::= assignment that declare lvalue with type and
value of rvalue.  In Sather 1.3 they are warning against this usage,
because it can lead to maintanance problems.
That's interesting. I didn't know about that feature in Sather. It's also interesting that they're now deprecating it. However I somehow doubt that they're deprecating it just because somebody managed to use it to botch up their code.
Sather 1.2 was develop by Berkeley http://www.icsi.berkeley.edu/~sather/index.html while 1.3 by Waikato http://www.cs.waikato.ac.nz/sather/ If you read the docs in both sites you operator now, and promoting the long usage: i.e. instead of #CPX(1,0) you use CPX.create(1,0). Like the Eiffel deprecated !! notation. Both languages are going towards explicit coding and verbosity IMO.
IMO it's better to make a simpler template
syntax than add another concept to to the same job.
I would tend to agree. I don't think I like it for function args.
If we can address the template problems first, we can focus our attention latter on other problems. Some kind of type inference would be wonderful but now it's too difficult to play with the type system and get something nice out of it. Best regards, Daniel Yokomiso. "Actually, C++ is being post-incremented, so this iteration C++ is the same as c, but next time around it'll be great!" - tfinniga at /. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 11/1/2003
Jan 17 2003
prev sibling next sibling parent Russell Lewis <spamhole-2001-07-16 deming-os.org> writes:
Daniel Yokomiso wrote:
 The first kind of var usage seems nice, but in practice I think it can lead to
 some obscure pieces of code. In the middle of a large method how are you going
 to interpret this:
 
 
 var foo = bar.testIt(baz, fred, 1, 1.9, "\");
Such a thing is where an IDE comes in to help. Put your mouse over 'var', and the IDE will tell you the type. Or, if you prefer, just have the IDE display the underlying type even though you just typed 'var'.
 With method overloading in D we need to verify the types of baz and fred so we
 can discover which version is used. If baz and fred are also var, it can be
 somewhat hard to understand what's going on.
Jan 16 2003
prev sibling next sibling parent "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
"Daniel Yokomiso" <Daniel_member pathlink.com> wrote in message
news:b06pjb$1kcf$1 digitaldaemon.com...
 Hi,

 The first kind of var usage seems nice, but in practice I think it can
lead to
 some obscure pieces of code. In the middle of a large method how are you
going
 to interpret this:
It's always possible to write obscure code. Doesn't mean you have to.
 var foo = bar.testIt(baz, fred, 1, 1.9, "\");
You have the same problem anyway; lack of named parameters is confusing enough by itself.
 With method overloading in D we need to verify the types of baz and fred
so we
 can discover which version is used. If baz and fred are also var, it can
be
 somewhat hard to understand what's going on.
You may not need to understand what's going on. IDE code browsing features are improving all the time anyway. Maybe your IDE would have an option to "bake in" all implicit variables, injecting the actual type name back into the source code. And not all uses are arcane. It'd probably find a lot of use when doing simple stuff.
 Some weeks ago a programming pissing contest was going on comp.arch and
someone
 said var is no longer than int. I agree that it's true that var is smaller
than
 almost anything else, but I don't think a new keyword is needed just for
this
 half-baked type-inference system.
:= would work fine.
 Sather 1.2 provides a ::= assignment that
 declare lvalue with type and value of rvalue. In Sather 1.3 they are
warning
 against this usage, because it can lead to maintanance problems. But
Sather has
 saner type names than C++, and builtin iterators, so they don't have the
 std::ListIterator<std::Set<String>> problem ;-)
It may even *increase* maintainability of code. If you change the parameters, all the implicit temp variables automatically change too (and if they change in a way that doesn't work, the compiler will tell you). It'd be great for use in templates when you don't know the actual type name anyway. Most of that could be taken care of by a typeof(x) or x.type() feature though. The only difference between x.type() y = x and y ::= x is one of syntactical sugar. y ::= x looks alot sweeter. Especially if the actual x is a rather complicated expression. The programmer's intent is clear; they want a named temporary variable. The first form clutters up this intent with syntactical baggage. Sather looks interesting semantically but I find the flavor of the syntax disturbing. I'll have to look into it more.
 The second usage is similar to current template mechanism, only terser.
But this
 is a problem of template verbosity. IMO it's better to make a simpler
template
 syntax than add another concept to to the same job.
 Just for the records, I like type system where inference is possible
(e.g.: ML
 or Haskell), but without unification we must always restrict inference to
some
 parts of the problem.
You could do some powerful stuff with type inference. So long as there are no declarative cycles. As with any feature that allows one to shoot themselves in the foot, care must be used to aim properly. Exercise: name one feature of C++ that can't possibly be used to shoot yourself in the foot, one way or another. ;) Sean
Jan 17 2003
prev sibling parent reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Daniel Yokomiso wrote:
 Sather 1.2 provides
 a ::= assignment that declare lvalue with type and value of rvalue. In
 Sather 1.3 they are warning against this usage, because it can lead to
 maintanance problems.
Careful: I was the maintainer of Sather during that time. I've done lots of code in Sather (a complete compiler written from scratch, at one time) and I can only speak in favor of that "::=" construct. I really urge everyone to consider the "var" suggestion. It definitely *improves* maintainability greatly. Of course, one can use that feature to produce unreadable code, but then, an expression where you can't infer the type by a quick glance is a bad idea anyway. If you've come to need the type written in variable declarations as documentation, you really have a much deeper problem. As an example for where I really hate the lack of such a possibility in C++ are iterators: for(Somecontainer<Sometype>::Reverse_iterator i = C.end();i;i--) { ... }; How about this: for(var i = C.end();i;i--) { ... }; Just consider you want to try out another container type and have to go through all your code to adjust the iterators. Of course, there are ways to avoid that, but they all need some overhead at some other place. Of course, in D, type inference is not always possible from an expression alone, but why not simply make the use of "var" an error in those cases? Ciao, Nobbi
Jan 17 2003
next sibling parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> wrote
in message news:b09ad9$30q8$1 digitaldaemon.com...
 Daniel Yokomiso wrote:
 Sather 1.2 provides
 a ::= assignment that declare lvalue with type and value of rvalue. In
 Sather 1.3 they are warning against this usage, because it can lead to
 maintanance problems.
Careful: I was the maintainer of Sather during that time. I've done lots
of
 code in Sather (a complete compiler written from scratch, at one time) and
 I can only speak in favor of that "::=" construct. I really urge everyone
 to consider the "var" suggestion. It definitely *improves* maintainability
 greatly. Of course, one can use that feature to produce unreadable code,
 but then, an expression where you can't infer the type by a quick glance
is
 a bad idea anyway. If you've come to need the type written in variable
 declarations as documentation, you really have a much deeper problem.
That's what I thought. ;) I believe I prefer a new operator such as := or ::= over the "var" keyword. "var" is more in-line with how C, C++, and D parse declarations though.
 Of course, in D, type inference is not always possible from an expression
 alone, but why not simply make the use of "var" an error in those cases?
Where is an D expression's type not 100% deterministic? It's never determined by the type of the result variable. So it must be determinable just from the expression itself and any declarations that are in scope. I can't think of a single example.
 Ciao,
 Nobbi
Jan 17 2003
next sibling parent reply Kimberley Burchett <kimbly at kimbly.com> <Kimberley_member pathlink.com> writes:
In article <b09jar$5na$1 digitaldaemon.com>, Sean L. Palmer says...
I believe I prefer a new operator such as := or ::= over the "var" keyword.
"var" is more in-line with how C, C++, and D parse declarations though.
I don't mind ::= and I generally like to use existing syntax if possible. However, it would look weird to use ::= for a return type. Example: &nbsp;&nbsp;&nbsp;&nbsp;::= add(SomeType x, SomeType y) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return x+y; &nbsp;&nbsp;&nbsp;&nbsp;} versus this: &nbsp;&nbsp;&nbsp;&nbsp;var add(SomeType x, SomeType y) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return x + y; &nbsp;&nbsp;&nbsp;&nbsp;} I think the word "var" already sucks as a return type, but ::= is even worse.
Where is an D expression's type not 100% deterministic?  It's never
determined by the type of the result variable.  So it must be determinable
just from the expression itself and any declarations that are in scope.  I
can't think of a single example.
recursive functions, if you allow var return types: &nbsp;&nbsp;&nbsp;&nbsp;var foo(SomeType x) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return foo(x+1)+x; &nbsp;&nbsp;&nbsp;&nbsp;}
Jan 17 2003
next sibling parent reply Kimberley Burchett <kimbly at kimbly.com> <Kimberley_member pathlink.com> writes:
Well I guess using &nbsp; didn't work.  Here it is again, probably
with all the indentation omitted :(

In article <b09jar$5na$1 digitaldaemon.com>, Sean L. Palmer says...
I believe I prefer a new operator such as := or ::= over the "var" keyword.
"var" is more in-line with how C, C++, and D parse declarations though.
I don't mind ::= and I generally like to use existing syntax if possible. However, it would look weird to use ::= for a return type. Example: ::= add(SomeType x, SomeType y) { return x+y; } versus this: var add(SomeType x, SomeType y) { return x + y; } I think the word "var" already sucks as a return type, but ::= is even worse.
Where is an D expression's type not 100% deterministic?  It's never
determined by the type of the result variable.  So it must be determinable
just from the expression itself and any declarations that are in scope.  I
can't think of a single example.
recursive functions, if you allow var return types: var foo(SomeType x) { return foo(x+1)+x; }
Jan 17 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Kimberley Burchett" <kimbly at kimbly.comKimberley_member pathlink.com>
wrote in message news:b0a8c3$iuq$1 digitaldaemon.com...
 ::= add(SomeType x, SomeType y) {
 return x+y;
 }
Inferring the return type of functions requires that the compiler be able to do the semantic analysis of the function before its type can be determined. This is a problem not only for the case of recursive function calls, but for the compiler when trying to figure out what order to do the semantic analysis of functions in. I don't think it will work.
Feb 14 2003
parent "Walter" <walter digitalmars.com> writes:
But the var idea does have a lot of merit if constrained to be for local
variables.
Feb 14 2003
prev sibling parent reply Norbert Nemec <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Kimberley Burchett wrote:

 In article <b09jar$5na$1 digitaldaemon.com>, Sean L. Palmer says...
I believe I prefer a new operator such as := or ::= over the "var"
keyword. "var" is more in-line with how C, C++, and D parse declarations
though.
I don't mind ::= and I generally like to use existing syntax if possible. However, it would look weird to use ::= for a return type. Example:
Please forget about using it for return types. One would need to take a look at the implementation to get the necessary information for the interface. It is nice for local variables, where declaration and "implementation" (i.e. the expression that actually determines the type) are always directly at the same place, but for nothing else. Allowing this "undeterminedness" to spread outside of the function scope woule really make the program unreadable, and in case of recursive functions, the compiler would not even able to determine any type at all.
Where is an D expression's type not 100% deterministic?  It's never
determined by the type of the result variable.  So it must be determinable
just from the expression itself and any declarations that are in scope.  I
can't think of a single example.
OK, true, the thing I was thinking of were struct initializers, but those are not really standard expressions...
Jan 17 2003
next sibling parent reply Kimberley Burchett <kimbly nospam.cybercom.net> writes:
Norbert Nemec wrote:
 Please forget about using it for return types. One would need to take a
 look at the implementation to get the necessary information for the
 interface.
Well of course! I wasn't intending to allow it for interfaces.
 Allowing this "undeterminedness" to spread outside of the function 
 scope woule really make the program unreadable, and in case of 
 recursive functions, the compiler would not even able to determine 
 any type at all.
I said earlier in this thread that I would disallow it for recursive functions, because that would require some kind of type solver. I don't know why you think I suggested letting the thing "spread outside of the function scope". If you want to object to it based on the fact that it would be significantly harder to implement for return values than for local variables, then I'm willing to take the point. I don't expect the return value thing to actually make it into D at this point. But the local variable thing might have a chance, and when considering what keyword to use, we might as well take into account where the feature might go in the future. Kimberley Burchett
Jan 17 2003
parent Norbert Nemec <Nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Kimberley Burchett wrote:

 Norbert Nemec wrote:
 Please forget about using it for return types. One would need to take a
 look at the implementation to get the necessary information for the
 interface.
Well of course! I wasn't intending to allow it for interfaces.
 Allowing this "undeterminedness" to spread outside of the function
 scope woule really make the program unreadable, and in case of
 recursive functions, the compiler would not even able to determine
 any type at all.
I said earlier in this thread that I would disallow it for recursive functions, because that would require some kind of type solver. I don't know why you think I suggested letting the thing "spread outside of the function scope". If you want to object to it based on the fact that it would be significantly harder to implement for return values than for local variables, then I'm willing to take the point. I don't expect the return value thing to actually make it into D at this point. But the local variable thing might have a chance, and when considering what keyword to use, we might as well take into account where the feature might go in the future.
Guess, we are completely in line at that point. Leave the "inferred types" feature just for the declaration of variables and put everything beyond that ot the section "dreams about the future". Personally I like the original "var" syntax most. It fits into D syntax far better than "::=" or any of the other suggestions.
Jan 18 2003
prev sibling parent reply Russell Lewis <spamhole-2001-07-16 deming-os.org> writes:
Norbert Nemec wrote:
 Kimberley Burchett wrote:
 
 
In article <b09jar$5na$1 digitaldaemon.com>, Sean L. Palmer says...

I believe I prefer a new operator such as := or ::= over the "var"
keyword. "var" is more in-line with how C, C++, and D parse declarations
though.
I don't mind ::= and I generally like to use existing syntax if possible. However, it would look weird to use ::= for a return type. Example:
Please forget about using it for return types. One would need to take a look at the implementation to get the necessary information for the interface. It is nice for local variables, where declaration and "implementation" (i.e. the expression that actually determines the type) are always directly at the same place, but for nothing else. Allowing this "undeterminedness" to spread outside of the function scope woule really make the program unreadable, and in case of recursive functions, the compiler would not even able to determine any type at all.
Don't be so quick to judge it. Often, APIs return "handles" and such. The user is NEVER supposed to access them, although they often are just typedef's of void pointers or unsigned integers. A function that returned handle could return var. Not sure if I like the idea or not, but it's worth considering, at least. The example is problematic because most of the time, you need to save the handle in a struct for later use; how do you declare a member of a struct when it's type is inferred?
Jan 21 2003
parent reply Norbert Nemec <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM> writes:
Russell Lewis wrote:

 Norbert Nemec wrote:
 Kimberley Burchett wrote:
 
 
In article <b09jar$5na$1 digitaldaemon.com>, Sean L. Palmer says...

I believe I prefer a new operator such as := or ::= over the "var"
keyword. "var" is more in-line with how C, C++, and D parse declarations
though.
I don't mind ::= and I generally like to use existing syntax if possible. However, it would look weird to use ::= for a return type. Example:
Please forget about using it for return types. One would need to take a look at the implementation to get the necessary information for the interface. It is nice for local variables, where declaration and "implementation" (i.e. the expression that actually determines the type) are always directly at the same place, but for nothing else. Allowing this "undeterminedness" to spread outside of the function scope woule really make the program unreadable, and in case of recursive functions, the compiler would not even able to determine any type at all.
Don't be so quick to judge it. Often, APIs return "handles" and such. The user is NEVER supposed to access them, although they often are just typedef's of void pointers or unsigned integers. A function that returned handle could return var.
But that doesn't fit at all with the meaning of "var" as discussed for local variable declaration. "var" is not an unknown type, but a definite type to be determined at compile time. It is semantically identical to specifying the type by hand. Just saves typing and editing whenever the type might change.
Jan 22 2003
parent Ilya Minkov <midiclub tiscali.de> writes:
Norbert Nemec wrote:
 
 But that doesn't fit at all with the meaning of "var" as discussed for local 
 variable declaration. "var" is not an unknown type, but a definite type to 
 be determined at compile time. It is semantically identical to specifying 
 the type by hand. Just saves typing and editing whenever the type might 
 change.
 
Particularly, in templates where it *has* to change, but shall be known at instantiation. And it might save one from picking up the CPUs native type to save the intermediate results of a calculation. -i.
Jan 22 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
news:b09jar$5na$1 digitaldaemon.com...
 Where is an D expression's type not 100% deterministic?  It's never
 determined by the type of the result variable.  So it must be determinable
 just from the expression itself and any declarations that are in scope.  I
 can't think of a single example.
There are two examples: 1) &func, where func is an overloaded function. Which overloaded function it is gets determined by type inference. 2) "string", where whether it is a wchar[] or char[] is determined by type inference. I really don't like either of those, but never found a palatable alternative. The first exists in C++, the second does not (as L"string" is used). I have some experience with C++ L strings, and the clumsy use of macros to convert back and forth, and found the result unacceptable.
Feb 14 2003
prev sibling parent "Daniel Yokomiso" <daniel_yokomiso yahoo.com.br> writes:
Hi,

   Comments embedded,

"Norbert Nemec" <nobbi_at_theorie3.physik.uni-erlangen.de NOSPAM.COM>
escreveu na mensagem news:b09ad9$30q8$1 digitaldaemon.com...
 Daniel Yokomiso wrote:
 Sather 1.2 provides
 a ::= assignment that declare lvalue with type and value of rvalue. In
 Sather 1.3 they are warning against this usage, because it can lead to
 maintanance problems.
Careful: I was the maintainer of Sather during that time. I've done lots
of
 code in Sather (a complete compiler written from scratch, at one time) and
 I can only speak in favor of that "::=" construct. I really urge everyone
 to consider the "var" suggestion. It definitely *improves* maintainability
 greatly. Of course, one can use that feature to produce unreadable code,
 but then, an expression where you can't infer the type by a quick glance
is
 a bad idea anyway. If you've come to need the type written in variable
 declarations as documentation, you really have a much deeper problem.
Nice to hear that we have some Sather developer here. Most of people came from an strictly C++ OO/Generics model. I've came accross this warning at Waikato documentation about Sather 1.3. I just pointed the fact, not saying some eternal truth.
 As an example for where I really hate the lack of such a possibility in
C++
 are iterators:

         for(Somecontainer<Sometype>::Reverse_iterator i = C.end();i;i--) {
                 ...
         };

 How about this:

         for(var i = C.end();i;i--) {
                 ...
         };
Well we can also do this: C.end().forEach(fun(i) {...}); or for (i in C.end()) { ... } or loop i ::= C.item! ... end ;-) Iteration is a problem when you have to create explicit "friend"-like classes to allow external iteration. IMO Sather iterators are one of the best possible ways of doing external iteration. If Sather had a simpler type system, where a Hindley-Milner unification was possible (and using streams with ! operator instead of anything ending with a !) it could have higher-order programming over iterators, using them as lazy languages use lazy lists. My pet language, Eon, has Sather-like iterators as basic types (along tuples and function types) so we can use map, filter, etc. with iterators, making any possible higher-order mapping over lists available to iterators. Someday I'll write a compiler for it. Iin D of course ;-) I know that multiple collection iteration is difficult with internal iterators, but Slate http://slate.tunes.org/ provides a multiple collection selector. But they're use dynamic typing and I think their implementation must be dynamically typed.
 Just consider you want to try out another container type and have to go
 through all your code to adjust the iterators. Of course, there are ways
to
 avoid that, but they all need some overhead at some other place.

 Of course, in D, type inference is not always possible from an expression
 alone, but why not simply make the use of "var" an error in those cases?

 Ciao,
 Nobbi
I don't like the feel of some language feature that sometimes is invalid because it's ambiguous. That's why I'm playing devil's advocate over this feature. Best regards, Daniel Yokomiso. P.S.: I never thought that post would bring more than one response. I guess people really abhor type declarations ;-) "Boss: "D?" What happened to C? Or that other one, C++, that you're always harping about? Me: Well, D is a further refinement of C++, and ... Boss: Weren't you just telling me that "J" language was supposed to be the next big thing? Isn't J further along than D? Me: Yes and no ... [suddenly, a shot rang out]" - sunwukong at /. --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.443 / Virus Database: 248 - Release Date: 11/1/2003
Jan 17 2003