digitalmars.D - Automatic typing
- JS (17/17) Jun 27 2013 Would it be possible for a language(specifically d) to have the
- Adam D. Ruppe (3/3) Jun 27 2013 I believe it would be possible. D does something similar for auto
- Steven Schveighoffer (23/38) Jun 27 2013 There are very good reasons not to do this, even if possible. Especiall...
- JS (40/83) Jun 27 2013 says who? No one is forcing you to use it with an immediate
- Steven Schveighoffer (23/110) Jun 28 2013 This is already defined:
- JS (13/18) Jun 28 2013 Using the auto keyword was just an example. My argument does not
- Steven Schveighoffer (23/36) Jun 28 2013 There is a possible way to solve this -- auto return types. If you can ...
- F i L (4/6) Jul 01 2013 +1
- bearophile (6/9) Jun 27 2013 Do you mean the flow-sensitive typing of the Whiley language?
- Jonathan M Davis (8/27) Jun 28 2013 Regardless of whether such a feature would be of value (and honestly, I'...
- deadalnix (3/35) Jun 28 2013 code flow analysis is require for @disable this. And this is the
- ponce (11/14) Jun 28 2013 Well ocaml has it
- bearophile (7/10) Jun 28 2013 I think a H-M global type inferencer is not needed for what the
- Timon Gehr (3/16) Jun 28 2013 ... at a few places.
- Brian Rogoff (27/42) Jun 28 2013 No, OCaml doesn't quite do what the OP is asking for. In
- bearophile (5/8) Jun 28 2013 I see, then this is not related to the flow typing I have linked
- Walter Bright (3/18) Jun 28 2013 I don't see a compelling use case for this proposal, or even any use cas...
- John Colvin (3/31) Jun 28 2013 My thoughts too. It's a lot of work for a very minor (and perhaps
- Timon Gehr (10/36) Jun 28 2013 Eg:
- Walter Bright (8/20) Jun 28 2013 Or:
- JS (24/52) Jun 28 2013 Is variant useful? If not then you have a point. I'm not
- Walter Bright (5/24) Jun 28 2013 Again, I need a compelling use case. It's not enough to say it's the sam...
- JS (2/45) Jun 28 2013 What was the use case for auto that got in into the language?
- John Colvin (4/52) Jun 28 2013 A quick look at any heavily templated c++ (pre c++11) is all you
- Walter Bright (11/12) Jun 28 2013 In code where the type of the initializer would change, and if the type ...
- JS (73/87) Jun 28 2013 I don't disagree with you and I'm not saying auto is not useful.
- Ivan Kazmenko (11/19) Jul 02 2013 Let me expand the example with this:
- Ary Borenszweig (24/39) Jun 29 2013 What you are asking is essentially what Crystal does for all variables
- Walter Bright (5/15) Jun 29 2013 Sorry, but that seems like a solution in search of a problem.
- Ary Borenszweig (2/24) Jun 29 2013 Sorry, but I can't imagine those bugs. Can you show me an example?
- Walter Bright (8/34) Jun 29 2013 Sure:
- Ary Borenszweig (8/43) Jun 29 2013 If the last statements were:
- Walter Bright (2/3) Jun 29 2013 Thanks. I remember seeing it somewhere before, but can't recall just whe...
- Steven Schveighoffer (22/44) Jun 29 2013 x is a variant that is compile-time optimized to be an int or a float. ...
- JS (56/106) Jun 30 2013 This is not what I am talking about and it seems quite dangerous
- Kenji Hara (22/25) Jun 30 2013 Just a simple matter, it would *drastically* increase compilation time.
- JS (16/53) Jun 30 2013 No, this would be a brute force approach. Only one "preprocessing
- Ary Borenszweig (15/58) Jul 01 2013 Believe me, it's not. Look at this:
- Timon Gehr (12/38) Jun 30 2013 The described strategy can easily result in non-termination, and which
- Steven Schveighoffer (3/14) Jun 30 2013 Ouch! That is better than Walter's case :)
- JS (5/66) Jun 30 2013 Sorry, it only results in non-termination if you don't check all
- Timon Gehr (10/31) Jun 30 2013 Why is this relevant? I was specifically responding to the method lined
- JS (12/48) Jun 30 2013 well duh, but it is quite a simple mathematical problem and your
- deadalnix (10/23) Jun 30 2013 As a compiler implementer, Timon is probably way more competent
- JS (3/29) Jul 01 2013 You can't be as smart as you think or you would know that "proof
- John Colvin (4/36) Jul 01 2013 Authority is not proof, but many years of experience provide a
- Ary Borenszweig (11/60) Jul 01 2013 Just tried it in Crystal and it ends alright. It works like this:
- Timon Gehr (13/76) Jul 01 2013 Using overloaded functions, I guess? It is not really the same thing,
- Walter Bright (2/4) Jun 30 2013 There are arguably not even small benefits.
- Ary Borenszweig (6/59) Jul 01 2013 Why dangerous? I've been programming in Ruby for quite a time and never
- Walter Bright (22/29) Jul 01 2013 D already disallows:
- Ary Borenszweig (48/79) Jul 01 2013 Well, those constructs don't even make sense because in the examples I
- John Colvin (7/37) Jul 01 2013 Why not this?
- Ary Borenszweig (3/8) Jul 01 2013 Ah, that's also ok. But then you have to remember to use myVar instead
- Walter Bright (19/26) Jul 01 2013 Heck, why bother with different variable names at all? We can just use x...
- Andrei Alexandrescu (4/8) Jul 01 2013 Reducing the number of names seems worthless, but increasing it can be
- John Colvin (15/23) Jul 01 2013 Personally I like the explicit use of a new variable. If you're
- Adam D. Ruppe (13/15) Jul 01 2013 I have wanted to remove a variable from scope before. I think it
- JS (45/80) Jul 01 2013 I'm not "proposing" this. There is only one variable.
- Timon Gehr (1/1) Jul 01 2013 Don't feed the troll.
- Walter Bright (11/17) Jul 01 2013 It's up to you to demonstrate your idea has merit. Throwing ideas out an...
- deadalnix (8/13) Jul 01 2013 For the record, this quote is plain wrong :
- Walter Bright (10/14) Jul 01 2013 None of us have to look very hard at ourselves to find such, if we're be...
- MattCoder (8/16) Jul 01 2013 I liked this answer:
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (3/6) Jul 01 2013 I still think so. :D
- Andrei Alexandrescu (33/63) Jul 01 2013 To me the basic notion was very clear from day one. Changing the type of...
- Walter Bright (11/25) Jul 01 2013 What is happening with (modern) compilers is the "live range" of each va...
- JS (28/118) Jul 01 2013 Too be honest, your reply seems to be the only one that attempts
- Andrei Alexandrescu (22/29) Jul 01 2013 I don't think such a feature would make it in D, even if the
- JS (47/82) Jul 01 2013 No, not under what I am talking about. You can't downgrade a
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (28/43) Jul 01 2013 I think I understand. I think I heard either on this or your other
- JS (40/95) Jul 01 2013 Yes, basically. If one coded for integers then decided to change
- Andrei Alexandrescu (7/41) Jul 01 2013 You can definitely assume you are being well understood. That's going to...
- Timon Gehr (13/23) Jul 01 2013 module b;
- Walter Bright (3/15) Jul 01 2013 I'd encourage you to submit an enhancement request that would produce th...
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.
Jun 27 2013
I believe it would be possible. D does something similar for auto return values on functions already. Might be a bit of work in the compiler though.
Jun 27 2013
On Thu, 27 Jun 2013 20:34:53 -0400, JS <js.mdnq gmail.com> 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.There are very good reasons not to do this, even if possible. Especially if the type can change. Consider this case: void foo(int); void foo(double); void main() { auto x; x = 5; foo(x); .... // way later down in main x = 6.0; } What version of foo should be called? By your logic, it should be the double version, but looking at the code, I can't reason about it. I have to read the whole function, and look at every usage of x. auto then becomes a liability, and not a benefit. Coupling the type of a variable with sparse usages is going to be extremely confusing and problematic. You are better off declaring the variable as a variant. -Steve
Jun 27 2013
On Friday, 28 June 2013 at 00:48:23 UTC, Steven Schveighoffer wrote:On Thu, 27 Jun 2013 20:34:53 -0400, JS <js.mdnq gmail.com> wrote:says who? No one is forcing you to use it with an immediate inference. If you get easily confused then simply declare x as a double in the first place! Most of the time a variable's type is well know by the programmer. That is, the programmer has some idea of the type a variable is to take on. Having the compiler infer the type is tantamount to figuring out what the programmer had in mind, in most cases this is rather easy to do... in any ambiguous case an error can be thrown.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.There are very good reasons not to do this, even if possible. Especially if the type can change. Consider this case: void foo(int); void foo(double); void main() { auto x; x = 5; foo(x); .... // way later down in main x = 6.0; } What version of foo should be called? By your logic, it should be the double version, but looking at the code, I can't reason about it. I have to read the whole function, and look at every usage of x. auto then becomes a liability, and not a benefit.Coupling the type of a variable with sparse usages is going to be extremely confusing and problematic. You are better off declaring the variable as a variant.If you are confused by the usage then don't use it. Just because for some programmers in some cases it is bad does not mean that it can't be useful to some programmers in some cases. Some programmers what to dumb down the compiler because they themselves want to limit all potential risk... What's amazing is that many times the features they are against does not have to be used in the first place. If you devise an extremely convoluted example then simply use a unit test or define the type explicitly. I don't think limiting the compiler feature set for the lowest common denominator is a way to develop a powerful language. You say using a variant type is better off, how? What is the difference besides performance? An auto type without immediate type inference offers all the benefits of static typing with some of those from a variant type... Since it seems you are not against variant then why would you be against a static version, since it actually offers more safety? In fact, my suggestion could simply be seen as an optimization of a variant type. e.g., variant x; x = 3; the compiler realizes that x can be reduced to an int type and sees the code as int x; x = 3; Hence, unless you are against variants and think they are evil(which contradicts your suggestion to use it), your argument fails.
Jun 27 2013
On Fri, 28 Jun 2013 02:51:39 -0400, JS <js.mdnq gmail.com> wrote:On Friday, 28 June 2013 at 00:48:23 UTC, Steven Schveighoffer wrote:This is already defined: auto x = 5; To change the meaning of that, would be unnecessarily confusing.On Thu, 27 Jun 2013 20:34:53 -0400, JS <js.mdnq gmail.com> wrote:says who? No one is forcing you to use it with an immediate inference. If you get easily confused then simply declare x as a double in the first place!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.There are very good reasons not to do this, even if possible. Especially if the type can change. Consider this case: void foo(int); void foo(double); void main() { auto x; x = 5; foo(x); .... // way later down in main x = 6.0; } What version of foo should be called? By your logic, it should be the double version, but looking at the code, I can't reason about it. I have to read the whole function, and look at every usage of x. auto then becomes a liability, and not a benefit.Most of the time a variable's type is well know by the programmer. That is, the programmer has some idea of the type a variable is to take on. Having the compiler infer the type is tantamount to figuring out what the programmer had in mind, in most cases this is rather easy to do... in any ambiguous case an error can be thrown.It's not the programmer I'm worried about. It's the maintainer/reviewer.But I use auto all the time, and I don't want its meaning to change.Coupling the type of a variable with sparse usages is going to be extremely confusing and problematic. You are better off declaring the variable as a variant.If you are confused by the usage then don't use it. Just because for some programmers in some cases it is bad does not mean that it can't be useful to some programmers in some cases.Some programmers what to dumb down the compiler because they themselves want to limit all potential risk... What's amazing is that many times the features they are against does not have to be used in the first place.As you have the compiler infer more and more, you lose it's ability to statically detect errors. This is the point of having a statically typed language. If you want loosey goosey semantics, you can use php.If you devise an extremely convoluted example then simply use a unit test or define the type explicitly. I don't think limiting the compiler feature set for the lowest common denominator is a way to develop a powerful language."simply" is an inaccurate description. Maintain any large project for some time in php and you will know what I mean.You say using a variant type is better off, how? What is the difference besides performance? An auto type without immediate type inference offers all the benefits of static typing with some of those from a variant type...It declares up front "this can change type mid-function". I don't have to read the whole function to guess it's type, it's a variant.Since it seems you are not against variant then why would you be against a static version, since it actually offers more safety?Variant is reasonable. It allows you to specify that you don't care about the type. And anything that takes variant can do the same. But in your scheme, the type is NOT I don't care, but basically defined by the compiler. Good luck discovering what it is. I see a lot of pragma(msg, typeof(x)) going to be put in that code.In fact, my suggestion could simply be seen as an optimization of a variant type. e.g., variant x; x = 3; the compiler realizes that x can be reduced to an int type and sees the code as int x; x = 3; Hence, unless you are against variants and think they are evil(which contradicts your suggestion to use it), your argument fails.My argument is that auto should be left the way it is. I don't want it to change. And variant already does what you want with less confusing semantics, no reason to add another feature. -Steve
Jun 28 2013
On Friday, 28 June 2013 at 14:02:07 UTC, Steven Schveighoffer wrote:On Fri, 28 Jun 2013 02:51:39 -0400, JS <js.mdnq gmail.com> My argument is that auto should be left the way it is. I don't want it to change. And variant already does what you want with less confusing semantics, no reason to add another feature. -SteveUsing the auto keyword was just an example. My argument does not depend the specific keyword used. My "idea" is simply generalizing auto to use forward inferencing. variant is NOT what I am talking about. It is not a performant time but a union of types. I am talking about the compiler finding the best choice for the type by looking ahead of the definition of the time. I think variant would be a good choice as my suggestion is a sort of optimization of variant. i.e., attempt to find the appropriate type at compile time, if not use a variant(or throw an error).
Jun 28 2013
On Fri, 28 Jun 2013 18:00:54 -0400, JS <js.mdnq gmail.com> wrote:On Friday, 28 June 2013 at 14:02:07 UTC, Steven Schveighoffer wrote:There is a possible way to solve this -- auto return types. If you can fit your initialization of the variable into a function (even an inner function) that returns auto, then the compiler should be able to figure out the best type. Example: import std.stdio; void main(string[] args) { auto foo() { if(args.length > 1 && args[1] == "1") return 1; else return 2.5; } auto x = foo(); writeln(typeof(x).stringof); } this outputs "double". Granted, it doesn't solve the "general" case, where you want to use x before it's initialized a second time, but I think that really is just a programming error -- use a different variable. -SteveOn Fri, 28 Jun 2013 02:51:39 -0400, JS <js.mdnq gmail.com> My argument is that auto should be left the way it is. I don't want it to change. And variant already does what you want with less confusing semantics, no reason to add another feature. -SteveUsing the auto keyword was just an example. My argument does not depend the specific keyword used. My "idea" is simply generalizing auto to use forward inferencing. variant is NOT what I am talking about. It is not a performant time but a union of types. I am talking about the compiler finding the best choice for the type by looking ahead of the definition of the time.
Jun 28 2013
Steven Schveighoffer wrote:There are very good reasons not to do this, even if possible. Especially if the type can change.+1 This sort of inference can only lead to problems down the line, IMO.
Jul 01 2013
JS: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.Do you mean the flow-sensitive typing of the Whiley language? http://whiley.org/guide/typing/flow-typing/ It's surely neat. But it needs flow analysis. Bye, bearophile
Jun 27 2013
On Friday, June 28, 2013 02:34:53 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.Regardless of whether such a feature would be of value (and honestly, I'm inclined to believe that it would do more harm than good), Walter would never go for it, because it would require code flow analysis, and he pretty much refuses to have that in the compiler or to have any feature which would require it in the language. So, while it may be technically feasible, it'll never happen. - Jonathan M Davis
Jun 28 2013
On Friday, 28 June 2013 at 07:04:12 UTC, Jonathan M Davis wrote:On Friday, June 28, 2013 02:34:53 JS wrote:code flow analysis is require for disable this. And this is the very reason why disable this is full of holes right now.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.Regardless of whether such a feature would be of value (and honestly, I'm inclined to believe that it would do more harm than good), Walter would never go for it, because it would require code flow analysis, and he pretty much refuses to have that in the compiler or to have any feature which would require it in the language. So, while it may be technically feasible, it'll never happen.
Jun 28 2013
On Friday, 28 June 2013 at 00:34:54 UTC, 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?Well ocaml has it (https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner) and well it's not all that positive, at least in that language. Combined with parametric polymorphism it's nice and sound, except it has the potential to hide a simple typo a lot further from where it is (think mixing up integer operators and FP operators). As it break overloading on "leaves", it is the reason ocaml has "print_string" and "print_int" which is quite frankly ugly. Once you have type inference, the first thing you do to make your code readable is to add back type annotations.
Jun 28 2013
ponce:Well ocaml has it (https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner) and well it's not all that positive, at least in that language.I think a H-M global type inferencer is not needed for what the OP is asking for, that is limited _inside_ functions, so it's not global. See the flow-typing link I have shown above (the links I add to threads aren't just for show). Bye, bearophile
Jun 28 2013
On 06/28/2013 03:44 PM, ponce wrote:On Friday, 28 June 2013 at 00:34:54 UTC, JS wrote:The type system might be too primitive in that regard. Haskell has 'print'.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?Well ocaml has it (https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner) and well it's not all that positive, at least in that language. Combined with parametric polymorphism it's nice and sound, except it has the potential to hide a simple typo a lot further from where it is (think mixing up integer operators and FP operators). As it break overloading on "leaves", it is the reason ocaml has "print_string" and "print_int" which is quite frankly ugly.Once you have type inference, the first thing you do to make your code readable is to add back type annotations.... at a few places.
Jun 28 2013
On Friday, 28 June 2013 at 13:44:19 UTC, ponce wrote:On Friday, 28 June 2013 at 00:34:54 UTC, JS wrote:No, OCaml doesn't quite do what the OP is asking for. In particular, the part where x is assigned an int and subsequently assigned a float can not be modeled directly. Even the separate 'auto x' and subsequent use of x is different from how OCaml's let polymorphism works. To model that, you could declare everything as 'a option refs and assign them later, like let main () = let x = ref None in let y = ref None in begin x := Some 1; y := Some (f()); end but if you want to use x as another type later you'll have to shadow the declaration in a new scope.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?Well ocaml has it (https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner) and well it's not all that positive, at least in that language.Combined with parametric polymorphism it's nice and sound, except it has the potential to hide a simple typo a lot further from where it is (think mixing up integer operators and FP operators). As it break overloading on "leaves", it is the reason ocaml has "print_string" and "print_int" which is quite frankly ugly.Yes, and the +., -., *., /. operators are ugly too, as is the requirement that record field labels in the same scope be distinct. Overloading can be dangerous, but no overloading is a PITA. Combining type inference and overloading is problematic.Once you have type inference, the first thing you do to make your code readable is to add back type annotations.There should always be a .mli file with exported decls. I wish OCaml had some ability to have separate type decls from the value, like Haskell. Type inference is most useful inside a function, IMO. I think that even if the feature being requested were feasible, it would be awful for D. -- Brian
Jun 28 2013
Brian Rogoff:No, OCaml doesn't quite do what the OP is asking for. In particular, the part where x is assigned an int and subsequently assigned a float can not be modeled directly.I see, then this is not related to the flow typing I have linked to, sorry. Bye, bearophile
Jun 28 2013
On 6/27/2013 5: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.I don't see a compelling use case for this proposal, or even any use case. There'd have to be some serious advantage to it to justify its complexity.
Jun 28 2013
On Friday, 28 June 2013 at 22:29:21 UTC, Walter Bright wrote:On 6/27/2013 5:34 PM, JS wrote:My thoughts too. It's a lot of work for a very minor (and perhaps rather unwise) convenience.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.I don't see a compelling use case for this proposal, or even any use case. There'd have to be some serious advantage to it to justify its complexity.
Jun 28 2013
On 06/29/2013 12:29 AM, Walter Bright wrote:On 6/27/2013 5:34 PM, JS wrote:Eg: auto a; if(x in cache) a=cache[x]; else cache[x]=a=new AnnoyingToSpellOutBeforeTheIf!"!"(); Using the type of the lexically first assignment would often be good enough, where reading the variable is disallowed prior to this first assignment. A little better (and still decidable) would be using the common type of all branches' first assignments not preceded by a read.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.I don't see a compelling use case for this proposal, or even any use case. There'd have to be some serious advantage to it to justify its complexity.
Jun 28 2013
On 6/28/2013 4:42 PM, Timon Gehr wrote:On 06/29/2013 12:29 AM, Walter Bright wrote:typeof(cache[x]) a; // (1)I don't see a compelling use case for this proposal, or even any use case. There'd have to be some serious advantage to it to justify its complexity.Eg: auto a;if(x in cache) a=cache[x]; else cache[x]=a=new AnnoyingToSpellOutBeforeTheIf!"!"();Or: auto a = (x in cache) ? cache[x] : (cache[x]=new AnnoyingToSpellOutBeforeTheIf!"!"()); // (2)Using the type of the lexically first assignment would often be good enough, where reading the variable is disallowed prior to this first assignment.So far, the use case is not compelling.A little better (and still decidable) would be using the common type of all branches' first assignments not preceded by a read.(1) handles that. Not every workaround needs a language feature.
Jun 28 2013
On Friday, 28 June 2013 at 22:29:21 UTC, Walter Bright wrote:On 6/27/2013 5:34 PM, JS wrote:Is variant useful? If not then you have a point. I'm not proposing anything that variant can't already do except add compile time performance. I do not think the complexity is much more than what is already done. D already checks for time mismatch. With such a variant or auto the check simply is more intelligent. e.g., auto x; // x's type is undefined or possibly variant. x = 3; // x's type is set temporarily to an int ... x = 3.0; // **** at **** we have several possibilities. 1. Throw an error, this makes auto more useful and avoids many pitfalls. 2. Set x's type to a variant. [possibly goto 3 if castable to new type] 3. Set x's type to a double. Both 2 and 3 require an extra pass to convert the code because it uses forward inference. auto looks only at the immediate assignment expression to determine the type. I am talking about generalizing it to look in the scope with possible fallback to a variant type with optional warning, an error, or type enlargement.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.I don't see a compelling use case for this proposal, or even any use case. There'd have to be some serious advantage to it to justify its complexity.
Jun 28 2013
On 6/28/2013 5:00 PM, JS wrote:Is variant useful? If not then you have a point. I'm not proposing anything that variant can't already do except add compile time performance. I do not think the complexity is much more than what is already done. D already checks for time mismatch. With such a variant or auto the check simply is more intelligent. e.g., auto x; // x's type is undefined or possibly variant. x = 3; // x's type is set temporarily to an int ... x = 3.0; // **** at **** we have several possibilities. 1. Throw an error, this makes auto more useful and avoids many pitfalls. 2. Set x's type to a variant. [possibly goto 3 if castable to new type] 3. Set x's type to a double. Both 2 and 3 require an extra pass to convert the code because it uses forward inference. auto looks only at the immediate assignment expression to determine the type. I am talking about generalizing it to look in the scope with possible fallback to a variant type with optional warning, an error, or type enlargement.Again, I need a compelling use case. It's not enough to say it's the same as variant, and it's not enough to say it can be implemented. A compelling use case would be a pattern that is commonplace, and for which the workarounds are ugly, unsafe, error prone, unportable, etc.
Jun 28 2013
On Saturday, 29 June 2013 at 01:31:13 UTC, Walter Bright wrote:On 6/28/2013 5:00 PM, JS wrote:What was the use case for auto that got in into the language?Is variant useful? If not then you have a point. I'm not proposing anything that variant can't already do except add compile time performance. I do not think the complexity is much more than what is already done. D already checks for time mismatch. With such a variant or auto the check simply is more intelligent. e.g., auto x; // x's type is undefined or possibly variant. x = 3; // x's type is set temporarily to an int ... x = 3.0; // **** at **** we have several possibilities. 1. Throw an error, this makes auto more useful and avoids many pitfalls. 2. Set x's type to a variant. [possibly goto 3 if castable to new type] 3. Set x's type to a double. Both 2 and 3 require an extra pass to convert the code because it uses forward inference. auto looks only at the immediate assignment expression to determine the type. I am talking about generalizing it to look in the scope with possible fallback to a variant type with optional warning, an error, or type enlargement.Again, I need a compelling use case. It's not enough to say it's the same as variant, and it's not enough to say it can be implemented. A compelling use case would be a pattern that is commonplace, and for which the workarounds are ugly, unsafe, error prone, unportable, etc.
Jun 28 2013
On Saturday, 29 June 2013 at 01:49:01 UTC, JS wrote:On Saturday, 29 June 2013 at 01:31:13 UTC, Walter Bright wrote:A quick look at any heavily templated c++ (pre c++11) is all you need to justify it. auto cuts code clutter by huge amounts all over the place.On 6/28/2013 5:00 PM, JS wrote:What was the use case for auto that got in into the language?Is variant useful? If not then you have a point. I'm not proposing anything that variant can't already do except add compile time performance. I do not think the complexity is much more than what is already done. D already checks for time mismatch. With such a variant or auto the check simply is more intelligent. e.g., auto x; // x's type is undefined or possibly variant. x = 3; // x's type is set temporarily to an int ... x = 3.0; // **** at **** we have several possibilities. 1. Throw an error, this makes auto more useful and avoids many pitfalls. 2. Set x's type to a variant. [possibly goto 3 if castable to new type] 3. Set x's type to a double. Both 2 and 3 require an extra pass to convert the code because it uses forward inference. auto looks only at the immediate assignment expression to determine the type. I am talking about generalizing it to look in the scope with possible fallback to a variant type with optional warning, an error, or type enlargement.Again, I need a compelling use case. It's not enough to say it's the same as variant, and it's not enough to say it can be implemented. A compelling use case would be a pattern that is commonplace, and for which the workarounds are ugly, unsafe, error prone, unportable, etc.
Jun 28 2013
On 6/28/2013 6:48 PM, JS wrote:What was the use case for auto that got in into the language?In code where the type of the initializer would change, and if the type of the variable was fixed, then there would be an unintended implicit conversion. The other use case was voldemort types. Such patterns are commonplace, and a source of error and inconvenience without auto. auto appears in various forms in other languages, and is almost universally lauded as worthwhile. These cases don't apply to this proposal, nor do I know of its successful adoption in another language. It's not a matter of finding reasons not to implement it. It's finding reasons TO implement it. Language features do not have zero cost - some benefit has to offset it.
Jun 28 2013
On Saturday, 29 June 2013 at 02:05:35 UTC, Walter Bright wrote:On 6/28/2013 6:48 PM, JS wrote:I don't disagree with you and I'm not saying auto is not useful. IMO though, auto is almost all convenience and very little to do with solving errors. A very simple use case is: auto x = 0; ... x = complex(1, 1) + x; which obviously is an error. By having auto use forward inferencing we can avoid such errors. It's obvious that x was intended to be a complex variable. Having auto look forward(or using a different keyword) reduces code refactoring and improves on the power of auto. for example suppose we use instead auto x = pow(2, 10); where pow returns a real. In this case x is still the wrong type. So we always have to know the "final" supertype anyways... I'm just proposing we let the compiler figure it out for us if we want. But because some types are supertypes of others it is entirely logical that they be extended when it is obvious the are being used as such. To see why this is even more useful, suppose we had such code above but now want to refactor to use quaternions. In this case, the line x = complex(1,1) + x is becomes invalid too and requires fixing(or the auto x line has to be fixed). If we allowed auto x; to easily see that it is suppose to be a quaternion then that line does not have to be fixed and everything would work as expected. So the real question is, is it error prone to allow the compiler to deduce what supertype a variable really is? I do not think it is a problem because ambiguity results in an error and warnings could be given when a variable type was upgraded to a super type. At some point, if flow analysis is ever added, auto would be a natural bridge to it. another useless case is auto someflag; static if (__cpu == 3) someflag = "amdx64" else someflag = false; which allows a sort of static variant type. (which could be gotten around if a static if conditional expression, e.g., static auto someflag = (__cpu == 3) ?? "amdx64" : false; ) The above may make it easier in some cases for configuration code. The biggest benefit I can immediately see comes from using mixins. In this case we can always have a variable select the appropriate type. e.g., mixin template Foo() { ((...) ?? int : float) func() { } } // func is of type int or float depending on the condition ... class Bar { auto x; // possibly auto x = default(typeof(func)); but possibly error prone due to refactoring if line order matters mixin Foo; static Bar() { x = default(typeof(func)); } } note that x's type is deduced at compile time to be the appropriate type corresponding to the mixin used. Because x's type does not have to be immediately known we can specify it implicitly later on without ever having to know the return types of the mixins. In this case Bar acts like a templated class but isn't(or is a sort of statically templated class so to speak) Such classes would be useful for versioning where the user of the class is oblivious to the types used in the class and does not need to specify a type parameter. e.g., The Bar class above could use int for a more performant version of the program and float for a more precise version. The use of auto would completely or near completely eliminate having to deal with which one is being used. In any case I can't specify any super duper use case because I don't know any.What was the use case for auto that got in into the language?In code where the type of the initializer would change, and if the type of the variable was fixed, then there would be an unintended implicit conversion. The other use case was voldemort types. Such patterns are commonplace, and a source of error and inconvenience without auto. auto appears in various forms in other languages, and is almost universally lauded as worthwhile. These cases don't apply to this proposal, nor do I know of its successful adoption in another language. It's not a matter of finding reasons not to implement it. It's finding reasons TO implement it. Language features do not have zero cost - some benefit has to offset it.
Jun 28 2013
On Saturday, 29 June 2013 at 03:20:27 UTC, JS wrote:I don't disagree with you and I'm not saying auto is not useful. IMO though, auto is almost all convenience and very little to do with solving errors. A very simple use case is: auto x = 0; ... x = complex(1, 1) + x; which obviously is an error.Let me expand the example with this: auto x = 0; complex y; ... x = complex(1, 1) + x; // ouch, I meant the next line! y = complex(1, 1) + x; Personally, I appreciate the strengths of static typing here, forcing me to choose which of the two behaviors I meant instead of silently picking one of them. Ivan Kazmenko.
Jul 02 2013
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 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.
Jun 29 2013
On 6/29/2013 12:18 PM, Ary Borenszweig wrote: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.Sorry, but that seems like a solution in search of a problem. And besides, yuk. Imagine the bugs caused by "hey, it doesn't implicitly convert, so instead of letting the user know he goofed, let's just silently create a new variable!"
Jun 29 2013
On 6/29/13 6:01 PM, Walter Bright wrote:On 6/29/2013 12:18 PM, Ary Borenszweig wrote:Sorry, but I can't imagine those bugs. Can you show me an example?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.Sorry, but that seems like a solution in search of a problem. And besides, yuk. Imagine the bugs caused by "hey, it doesn't implicitly convert, so instead of letting the user know he goofed, let's just silently create a new variable!"
Jun 29 2013
On 6/29/2013 2:53 PM, Ary Borenszweig wrote:On 6/29/13 6:01 PM, Walter Bright wrote:Sure: x = 3 px = &x y = f() x = 3.9 // uh-oh, *px points to a different x, and wasn't updated! printf("%d\n", x); // uh-oh, I thought x was an int!On 6/29/2013 12:18 PM, Ary Borenszweig wrote:Sorry, but I can't imagine those bugs. Can you show me an example?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.Sorry, but that seems like a solution in search of a problem. And besides, yuk. Imagine the bugs caused by "hey, it doesn't implicitly convert, so instead of letting the user know he goofed, let's just silently create a new variable!"
Jun 29 2013
On 6/29/13 7:30 PM, Walter Bright wrote:On 6/29/2013 2:53 PM, Ary Borenszweig wrote:If the last statements were: x = 4 printf("%d\n", *px); I can see where the problem is (you would expect that to print 4, right?). That can be easily fixed by not transforming the last x to SSA if its address is taken. That's a really good example you gave :-)On 6/29/13 6:01 PM, Walter Bright wrote:Sure: x = 3 px = &x y = f() x = 3.9 // uh-oh, *px points to a different x, and wasn't updated! printf("%d\n", x); // uh-oh, I thought x was an int!On 6/29/2013 12:18 PM, Ary Borenszweig wrote:Sorry, but I can't imagine those bugs. Can you show me an example?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.Sorry, but that seems like a solution in search of a problem. And besides, yuk. Imagine the bugs caused by "hey, it doesn't implicitly convert, so instead of letting the user know he goofed, let's just silently create a new variable!"
Jun 29 2013
On 6/29/2013 4:08 PM, Ary Borenszweig wrote:That's a really good example you gave :-)Thanks. I remember seeing it somewhere before, but can't recall just where.
Jun 29 2013
On Sat, 29 Jun 2013 17:01:54 -0400, Walter Bright <newshound2 digitalmars.com> wrote:On 6/29/2013 12:18 PM, Ary Borenszweig wrote:x is a variant that is compile-time optimized to be an int or a float. Where would the bug be? If x could possibly change types depending on runtime data, then x is given a type of a union between int or float. It would be somewhat like the compiler optimizing this: { Variant v = 1; v = 3.5; } to: { int v = 1; } { float v = 3.5; } because it sees that during the optimized scopes, v is only used as that specific type. It seems like the compiler is generating variants that can hold exactly the types that are used for that variable. Interesting concept. -SteveWhat 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.Sorry, but that seems like a solution in search of a problem. And besides, yuk. Imagine the bugs caused by "hey, it doesn't implicitly convert, so instead of letting the user know he goofed, let's just silently create a new variable!"
Jun 29 2013
On Saturday, 29 June 2013 at 19:18:13 UTC, Ary Borenszweig wrote:On 6/27/13 9:34 PM, JS wrote: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);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 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.
Jun 30 2013
2013/7/1 JS <js.mdnq gmail.com>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)Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji Hara
Jun 30 2013
On Monday, 1 July 2013 at 01:08:49 UTC, Kenji Hara wrote:2013/7/1 JS <js.mdnq gmail.com>No, this would be a brute force approach. Only one "preprocessing pass" of (#lines) would be required. Since parsing statement by statement already takes place, it should be an insignificant cost. arr is of of type *typeof(elem), when elem is known arr is immediately known. One would have to create a dependency tree but this is relatively simple and in most cases the tree's would be very small. The type of elem is known in one pass since we just have to scan statement by statement and update elem's type(using if (newtype > curtype) curtype = newtype). At the end of the scope elem's type is known and the dependency tree can be updated. The complexity of the algorithm would be small since each additional *autoscope* variable would not add much additional computation(just updating the type... we have to scan the scope anyways).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)Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji Hara
Jun 30 2013
On 6/30/13 10:30 PM, JS wrote:On Monday, 1 July 2013 at 01:08:49 UTC, Kenji Hara wrote:Believe me, it's not. Look at this: --- int foo(int elem) { return 1; } char foo(float elem) { return 'a'; } auto elem; elem = 1; auto other = foo(elem); elem = other + 2.5; --- Explain to me how the compiler would work in this case, step by step.2013/7/1 JS <js.mdnq gmail.com>No, this would be a brute force approach. Only one "preprocessing pass" of (#lines) would be required. Since parsing statement by statement already takes place, it should be an insignificant cost.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)Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji Hara
Jul 01 2013
On 07/01/2013 03:08 AM, Kenji Hara wrote:2013/7/1 JS <js.mdnq gmail.com <mailto:js.mdnq gmail.com>> 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) Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji HaraThe described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }
Jun 30 2013
On Sun, 30 Jun 2013 21:56:21 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:The described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }Ouch! That is better than Walter's case :) -Steve
Jun 30 2013
On Monday, 1 July 2013 at 01:56:22 UTC, Timon Gehr wrote:On 07/01/2013 03:08 AM, Kenji Hara wrote:Sorry, it only results in non-termination if you don't check all return types out of a function. It is a rather easy case to handle by just following all the return types and choosing the largest one. No big deal... any other tries?2013/7/1 JS <js.mdnq gmail.com <mailto:js.mdnq gmail.com>> 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) Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji HaraThe described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }
Jun 30 2013
On 07/01/2013 05:44 AM, JS wrote:On Monday, 1 July 2013 at 01:56:22 UTC, Timon Gehr wrote:That's fine.... The described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }Sorry,it only results in non-termination if you don't check all return types out of a function.Why is this relevant? I was specifically responding to the method lined out in the post I was answering. There have not been any other attempts to formalize the proposal so far.It is a rather easy case to handle by just following all the return types and choosing the largest one.That neither handles the above case in a sensible way nor is it a solution for the general issue. (Hint: D's type system is Turing complete.)No big deal... any other tries?That's not how it goes. The proposed inference method has to be completely specified for all instances, not only for those instances that I can be bothered to provide to you as counterexamples.
Jun 30 2013
On Monday, 1 July 2013 at 04:19:51 UTC, Timon Gehr wrote:On 07/01/2013 05:44 AM, JS wrote:well duh, but it is quite a simple mathematical problem and your counter-example is not one at all. For a statically typed language all types must be known at compile time... so you can't come up with any valid counter-example. Just because you come up with some convoluted example that seems to break the algorithm does not prove anything. Do you agree that a function's return type must be known at compile time in a statically typed language? If not then we have nothing more to discuss... (Just because you allow a function to be compile time polymorphic doesn't change anything because each type that a function can possibly return must be known)On Monday, 1 July 2013 at 01:56:22 UTC, Timon Gehr wrote:That's fine.... The described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }Sorry,it only results in non-termination if you don't check all return types out of a function.Why is this relevant? I was specifically responding to the method lined out in the post I was answering. There have not been any other attempts to formalize the proposal so far.It is a rather easy case to handle by just following all the return types and choosing the largest one.That neither handles the above case in a sensible way nor is it a solution for the general issue. (Hint: D's type system is Turing complete.)No big deal... any other tries?That's not how it goes. The proposed inference method has to be completely specified for all instances, not only for those instances that I can be bothered to provide to you as counterexamples.
Jun 30 2013
On Monday, 1 July 2013 at 06:38:20 UTC, JS wrote:well duh, but it is quite a simple mathematical problem and your counter-example is not one at all. For a statically typed language all types must be known at compile time... so you can't come up with any valid counter-example. Just because you come up with some convoluted example that seems to break the algorithm does not prove anything. Do you agree that a function's return type must be known at compile time in a statically typed language? If not then we have nothing more to discuss... (Just because you allow a function to be compile time polymorphic doesn't change anything because each type that a function can possibly return must be known)As a compiler implementer, Timon is probably way more competent than you are on the question. You'll get anything interesting to add by considering you know better. The type of problem he mention are already present in many aspect of D and makes it really hard to compile in a consistent way accross implementations. Adding new one is a really bad idea. If you don't understand what the problem is, I suggest you to study the question or ask questions rather than try to make a point.
Jun 30 2013
On Monday, 1 July 2013 at 06:51:53 UTC, deadalnix wrote:On Monday, 1 July 2013 at 06:38:20 UTC, JS wrote:You can't be as smart as you think or you would know that "proof by authority" is a fallacy.well duh, but it is quite a simple mathematical problem and your counter-example is not one at all. For a statically typed language all types must be known at compile time... so you can't come up with any valid counter-example. Just because you come up with some convoluted example that seems to break the algorithm does not prove anything. Do you agree that a function's return type must be known at compile time in a statically typed language? If not then we have nothing more to discuss... (Just because you allow a function to be compile time polymorphic doesn't change anything because each type that a function can possibly return must be known)As a compiler implementer, Timon is probably way more competent than you are on the question. You'll get anything interesting to add by considering you know better. The type of problem he mention are already present in many aspect of D and makes it really hard to compile in a consistent way accross implementations. Adding new one is a really bad idea. If you don't understand what the problem is, I suggest you to study the question or ask questions rather than try to make a point.
Jul 01 2013
On Monday, 1 July 2013 at 09:31:04 UTC, JS wrote:On Monday, 1 July 2013 at 06:51:53 UTC, deadalnix wrote:Authority is not proof, but many years of experience provide a perspective that is worth serious consideration. Which is what deadalnix said.On Monday, 1 July 2013 at 06:38:20 UTC, JS wrote:You can't be as smart as you think or you would know that "proof by authority" is a fallacy.well duh, but it is quite a simple mathematical problem and your counter-example is not one at all. For a statically typed language all types must be known at compile time... so you can't come up with any valid counter-example. Just because you come up with some convoluted example that seems to break the algorithm does not prove anything. Do you agree that a function's return type must be known at compile time in a statically typed language? If not then we have nothing more to discuss... (Just because you allow a function to be compile time polymorphic doesn't change anything because each type that a function can possibly return must be known)As a compiler implementer, Timon is probably way more competent than you are on the question. You'll get anything interesting to add by considering you know better. The type of problem he mention are already present in many aspect of D and makes it really hard to compile in a consistent way accross implementations. Adding new one is a really bad idea. If you don't understand what the problem is, I suggest you to study the question or ask questions rather than try to make a point.
Jul 01 2013
On 6/30/13 10:56 PM, Timon Gehr wrote:On 07/01/2013 03:08 AM, Kenji Hara wrote:Just tried it in Crystal and it ends alright. It works like this: 1. x is an Int 2. you call foo(x), it returns a float so x is now a float (right now in Crystal that's a union of int and float, but that will soon change). 3. Since x is a float, foo returns an int, but assigning it to x, which is already a float, gives back a float. 4. No type changed, so we end. Crystal also supports recursive and mutuilly recursive functions. The compiler is always guaranteed to finish. (I'm just using Crystal as an example to have a proof that it can be done)2013/7/1 JS <js.mdnq gmail.com <mailto:js.mdnq gmail.com>> 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) Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji HaraThe described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }
Jul 01 2013
On 07/01/2013 03:44 PM, Ary Borenszweig wrote:On 6/30/13 10:56 PM, Timon Gehr wrote:Using overloaded functions, I guess? It is not really the same thing, because those need to be type checked in any case.On 07/01/2013 03:08 AM, Kenji Hara wrote:Just tried it in Crystal2013/7/1 JS <js.mdnq gmail.com <mailto:js.mdnq gmail.com>> 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) Just a simple matter, it would *drastically* increase compilation time. void foo() { auto elem; auto arr = [elem]; elem = 1; .... elem = 2.0; // typeof(elem) change should modify the result of typeof(arr) } Such type dependencies between multiple variables are common in the realistic program. When `elem = 2.0;` is found, compiler should run semantic analysis of the whole function body of foo _once again_, because the setting type of elem ignites the change of typeof(arr), and it would affect the code meaning. If another variable type would be modified, it also ignites the whole function body semantic again. After all, semantic analysis repetition would drastically increase. I can easily imagine that the compilation cost would not be worth the small benefits. Kenji HaraThe described strategy can easily result in non-termination, and which template instantiations it performs can be non-obvious. auto foo(T)(T arg){ static if(is(T==int)) return 1.0; else return 1; } void main(){ auto x; x = 1; x = foo(x); }and it ends alright.(Note that I was specifically addressing the method Kenji Hara lined out, which appears to completely restart type checking every time a type changes.)It works like this: 1. x is an Int 2. you call foo(x), it returns a float so x is now a float (right now in Crystal that's a union of int and float, but that will soon change). 3. Since x is a float, foo returns an int, but assigning it to x, which is already a float, gives back a float. 4. No type changed, so we end. ...This kind of fixed-point iteration will terminate in D in most relevant cases (it is possible to create an infinitely ascending chain of types, but then, type checking failing implicit conversions won't terminate anyway). But note that now x is a double even though it is only assigned ints. Furthermore, this approach still implicitly instantiates template versions that are not referred to in the final type checked code.
Jul 01 2013
On 6/30/2013 6:08 PM, Kenji Hara wrote:I can easily imagine that the compilation cost would not be worth the small benefits.There are arguably not even small benefits.
Jun 30 2013
On 6/30/13 7:39 PM, JS wrote:On Saturday, 29 June 2013 at 19:18:13 UTC, Ary Borenszweig wrote:Why dangerous? I've been programming in Ruby for quite a time and never found it to be a problem, but an advantage. Now I'm programming in Crystal and it's the same, but the compiler can catch some errors too. Show me an example where this is dangerous (the pointer example gave by Walter is not valid anymore since it has a fix).On 6/27/13 9:34 PM, JS wrote:This is not what I am talking about and it seems quite dangerous to have one variable name masquerade as multiple variables.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 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.
Jul 01 2013
On 7/1/2013 6:39 AM, Ary Borenszweig wrote:D already disallows: int x; { float x; } as an error-prone construct, so why should it allow: int x; float x; ?This is not what I am talking about and it seems quite dangerous to have one variable name masquerade as multiple variables.Why dangerous?I've been programming in Ruby for quite a time and never found it to be a problem, but an advantage.What advantage? Does Ruby have a shortage of names for variables? (Early versions of BASIC only allowed variable names with one letter, leading to some pretty awful workarounds.)Show me an example where this is dangerous (the pointer example gave by Walter is not valid anymore since it has a fix).I'm actually rather sure that one can come up with rule after rule to 'fix' each issue, but good luck with trying to fit all those rules into some sort of comprehensible framework. Consider what happened to C++ when they tried to fit new things into the overloading rules - the rules now span multiple pages of pretty arbitrary rules, and practically nobody understands the whole. What people do is randomly try things until it seems to do the right thing for them, and then they move on. And all this for what - nobody has come up with a significant reason to support this proposal. I see post after post in this thread trying to make it work, and nothing about what problem it solves.
Jul 01 2013
On 7/1/13 1:15 PM, Walter Bright wrote:On 7/1/2013 6:39 AM, Ary Borenszweig wrote:Well, those constructs don't even make sense because in the examples I gave I never say what type I want my variables to be. I let the compiler figure it out.D already disallows: int x; { float x; } as an error-prone construct, so why should it allow: int x; float x; ?This is not what I am talking about and it seems quite dangerous to have one variable name masquerade as multiple variables.Why dangerous?I'll give you an example: def foo(var) var = var.to_s end I can call it like this: foo(1) foo("hello") If I had to put types, I would end up doing of of these: 1. void foo(int var) { foo(to!string(var)) } void foo(string var) { // do something with var } 2. void foo(T)(T var) { string myVar; static if (is(T == string)) { myVar = var; } else if (is(T == int)) { myVar = to!string(var) } else { static assert(false); } // do something with myVar } Both examples are ugly and verbose (or, at least, the example in Ruby/Crystal is much shorter and cleaner). The example I give is very simple, I can reuse a var which *has the same meaning* for me when I'm coding and I don't need to come up with a new name. It's not that Ruby has a shortage of names. It's just that I don't want to spend time thinking new, similar names, just to satisfy the compiler. (And if you are worried about efficiency, the method "#to_s" of String just returns itself, so in the end it compiles to the same code you could have written manually like I showed in D)I've been programming in Ruby for quite a time and never found it to be a problem, but an advantage.What advantage? Does Ruby have a shortage of names for variables? (Early versions of BASIC only allowed variable names with one letter, leading to some pretty awful workarounds.)Exactly, because in D you need to specify the types of variables. And that goes against inferring a variable's type from its usage (which is different from inferring it from its initializer). I'm also against this proposal. I'm just saying that in D it's not feasible, and if you want to make it work you'll have to change so many things that you'll end up with a different language.Show me an example where this is dangerous (the pointer example gave by Walter is not valid anymore since it has a fix).I'm actually rather sure that one can come up with rule after rule to 'fix' each issue, but good luck with trying to fit all those rules into some sort of comprehensible framework. Consider what happened to C++ when they tried to fit new things into the overloading rules - the rules now span multiple pages of pretty arbitrary rules, and practically nobody understands the whole. What people do is randomly try things until it seems to do the right thing for them, and then they move on. And all this for what - nobody has come up with a significant reason to support this proposal. I see post after post in this thread trying to make it work, and nothing about what problem it solves.
Jul 01 2013
On Monday, 1 July 2013 at 16:33:56 UTC, Ary Borenszweig wrote:I'll give you an example: def foo(var) var = var.to_s string end I can call it like this: foo(1) foo("hello") If I had to put types, I would end up doing of of these: 1. void foo(int var) { foo(to!string(var)) } void foo(string var) { // do something with var } 2. void foo(T)(T var) { string myVar; static if (is(T == string)) { myVar = var; } else if (is(T == int)) { myVar = to!string(var) } else { static assert(false); } // do something with myVar }Why not this? void foo(T)(T var) { auto myVar = var.to!string; //do something with myVar string }
Jul 01 2013
On 7/1/13 1:45 PM, John Colvin wrote:T)(T var) { auto myVar = var.to!string; //do something with myVar string }Ah, that's also ok. But then you have to remember to use myVar instead of var.
Jul 01 2013
On 7/1/2013 9:46 AM, Ary Borenszweig wrote:On 7/1/13 1:45 PM, John Colvin wrote:Heck, why bother with different variable names at all? We can just use x for all variables, t for all types, and f for all functions! t f(t x) { t x; t x = x & 0xFF; if (x == x) x = 0; else if ((x & 0xFFFD00) == 0x0F3800) x = x[(x >> 8) & 0xFF]; else if ((x & 0xFF00) == 0x0F00) x = x[x]; else x = x[x]; return x & x; } Sorry for the sarcasm, but I just don't get the notion that it's a burden to use a different name for a variable that has a different type and a different purpose. I'd go further and say it is a bad practice to use the same name for such.T)(T var) { auto myVar = var.to!string; //do something with myVar string }Ah, that's also ok. But then you have to remember to use myVar instead of var.
Jul 01 2013
On 7/1/13 9:59 AM, Walter Bright wrote:Sorry for the sarcasm, but I just don't get the notion that it's a burden to use a different name for a variable that has a different type and a different purpose. I'd go further and say it is a bad practice to use the same name for such.Reducing the number of names seems worthless, but increasing it can be quite annoying. Andrei
Jul 01 2013
On Monday, 1 July 2013 at 16:46:57 UTC, Ary Borenszweig wrote:On 7/1/13 1:45 PM, John Colvin wrote:Personally I like the explicit use of a new variable. If you're changing the type of a variable then you want it to be explicit. I spend far too many hours a month chasing down accidental type changes in python. A "convenience" feature is only a feature if it helps *stop* you shooting yourself in the foot, not if it actively encourages it. auto a; //loads of code, with function calls to all sorts of unfamiliar libraries //do something with a. How do I know what type a is to work with? I have to either read and understand all the code in between, try and write something generic, or put a pragma(msg, ...) in to show it for me. Either way I have to pray that nobody changes it.T)(T var) { auto myVar = var.to!string; //do something with myVar string }Ah, that's also ok. But then you have to remember to use myVar instead of var.
Jul 01 2013
On Monday, 1 July 2013 at 16:46:57 UTC, Ary Borenszweig wrote:Ah, that's also ok. But then you have to remember to use myVar instead of var.I have wanted to remove a variable from scope before. I think it would be kinda cool if we could do something like __undefine(x), and subsequent uses of it would be an error. (It could also prohibit redeclaration of it if we wanted.) D doesn't have that, but we can get reasonably close using other functions when we change param types (just forward it to the other overload) and functions and/or scopes for local variables: void foo() { { int a; /* use a */ } // a is now gone, so you don't accidentally use it later in the function }
Jul 01 2013
On Monday, 1 July 2013 at 16:15:04 UTC, Walter Bright wrote:On 7/1/2013 6:39 AM, Ary Borenszweig wrote:I'm not "proposing" this. There is only one variable. I think there is big confusion in what I'm "suggesting"(it's not a proposal because I don't expect anyone to take the time to prove its validity... and you can't know how useful it could be if you don't have any way to test it out). It's two distinctly different concepts when you allow a "multi-variable" and one that can be "up-typed" by inference(the compiler automatically "up-types").D already disallows: int x; { float x; } as an error-prone construct, so why should it allow: int x; float x; ?This is not what I am talking about and it seems quite dangerous to have one variable name masquerade as multiple variables.Why dangerous?I'm more interested in a true counterexample where my concept(which I've not seen in any language before) results in an invalid context.... and not a naive example that uses a half baked implementation of the algorithm(which I've already outlined). Just because someone comes up with an example and says "this will produce a non-termination" doesn't mean it will except in the most naive implementations. The problem is when such a "idea" is present you get people who are automatically against it for various irrational fears and they won't take any serious look at it to see if it has any merit... If you jump to the conclusion that something is useless without any real thought on it then it obviously is... but the same type of mentality has been used to "prove" just about anything was useless at one time or another. (and if that mentality ruled we'd still be using 640k of memory) I have a very basic question for you and would like a simple answer: In some programming languages, one can do the following type of code: var x; // x is some type of variable that holds data. It's type is not statically defined and can change at run time. x = 3; // x holds some type of number... usually an integer but the language may store all numbers as doubles or even strings. now, suppose we have a program that contains essentially the following: var x; x = 3; Is it possible that the compiler can optimize such code to find the least amount of data to represent x without issue? Yes or no? Is this a good thing? Yes or no? (I don't need and don't want any explanation) (the above example is at the heart of the matter... regardless if it is probably a valid semantic in D or easily to implement(since no one knows and most don't care because they think it won't benefit them(just like how bill gates thought all everyone needed was 640k)))I've been programming in Ruby for quite a time and never found it to be a problem, but an advantage.What advantage? Does Ruby have a shortage of names for variables? (Early versions of BASIC only allowed variable names with one letter, leading to some pretty awful workarounds.)Show me an example where this is dangerous (the pointer example gave by Walter is not valid anymore since it has a fix).I'm actually rather sure that one can come up with rule after rule to 'fix' each issue, but good luck with trying to fit all those rules into some sort of comprehensible framework. Consider what happened to C++ when they tried to fit new things into the overloading rules - the rules now span multiple pages of pretty arbitrary rules, and practically nobody understands the whole. What people do is randomly try things until it seems to do the right thing for them, and then they move on. And all this for what - nobody has come up with a significant reason to support this proposal. I see post after post in this thread trying to make it work, and nothing about what problem it solves.
Jul 01 2013
On 7/1/2013 9:57 AM, JS wrote:The problem is when such a "idea" is present you get people who are automatically against it for various irrational fears and they won't take any serious look at it to see if it has any merit... If you jump to the conclusion that something is useless without any real thought on it then it obviously is... but the same type of mentality has been used to "prove" just about anything was useless at one time or another.It's up to you to demonstrate your idea has merit. Throwing ideas out and asking others to find the merit for you is not going to work. It's even worse when you insult them for not finding the merit that you didn't find. Once you demonstrate merit then go about finding ways to make it work. Not the other way around. There are famous cases in business history where a solution was found before anyone identified a problem - 3M's not-very-sticky adhesive that was eventually turned into the hugely profitable postit notes is an example - but it languished for nearly a decade before someone thought of a use for it. And 3M certainly didn't productize it before the problem was discovered.
Jul 01 2013
On Monday, 1 July 2013 at 16:57:53 UTC, JS wrote:(the above example is at the heart of the matter... regardless if it is probably a valid semantic in D or easily to implement(since no one knows and most don't care because they think it won't benefit them(just like how bill gates thought all everyone needed was 640k)))For the record, this quote is plain wrong : https://groups.google.com/forum/#!msg/alt.folklore.computers/mpjS-h4jpD8/9DW_VQVLzpkJ But if you one very stupid one, I declared in the late 90s that a phone with a tactile screen on its whole surface was a stupid idea and that it would never work. I you look hard enough, I guess we all said the most stupid thing at some point. We got to admit it and not repeat the mistake.
Jul 01 2013
On 7/1/2013 10:51 AM, deadalnix wrote:But if you one very stupid one, I declared in the late 90s that a phone with a tactile screen on its whole surface was a stupid idea and that it would never work. I you look hard enough, I guess we all said the most stupid thing at some point. We got to admit it and not repeat the mistake.None of us have to look very hard at ourselves to find such, if we're being remotely honest. I don't much care for the popular "gotcha" practice of digging up something someone did or said decades ago. It presumes that we are all born wise, and offers no hope for learning from our mistakes. Sadly, the internet and the surveillance state are going to make life difficult for anyone trying to live down something stupid. Makes me glad I grew up before the internet. Makes me glad that most of the drivel I posted to Usenet back in the 80's has been hopefully lost :-)
Jul 01 2013
On Monday, 1 July 2013 at 17:51:02 UTC, deadalnix wrote:On Monday, 1 July 2013 at 16:57:53 UTC, JS wrote:I liked this answer: " QUESTION: I read in a newspaper that in 1981 you said, "640K should be enough for anybody." I always thought he was talking about his monthly bonus, not computer memory... " :) Matheus.(the above example is at the heart of the matter... regardless if it is probably a valid semantic in D or easily to implement(since no one knows and most don't care because they think it won't benefit them(just like how bill gates thought all everyone needed was 640k)))For the record, this quote is plain wrong : https://groups.google.com/forum/#!msg/alt.folklore.computers/mpjS-h4jpD8/9DW_VQVLzpkJ
Jul 01 2013
On 07/01/2013 10:51 AM, deadalnix wrote:I declared in the late 90s that a phone with a tactile screen on its whole surface was a stupid idea and that it would never work.I still think so. :D Ali
Jul 01 2013
On 7/1/13 9:57 AM, JS wrote:I think there is big confusion in what I'm "suggesting"(it's not a proposal because I don't expect anyone to take the time to prove its validity... and you can't know how useful it could be if you don't have any way to test it out). It's two distinctly different concepts when you allow a "multi-variable" and one that can be "up-typed" by inference(the compiler automatically "up-types").To me the basic notion was very clear from day one. Changing the type of a variable is equivalent with "unaliasing" the existing variable (i.e. destroy it and force it out of the symbol table) and defining an entirely different variable, with its own lifetime. It just so happens it has the same name. It's a reasonable feature to have -- a nice cheat that brings a statically-typed language closer to the look-and-feel of dynamic languages. Saves on names, which is more helpful than one might think. In D things like overloading and implicit conversions would probably make it too confusing to be useful.I'm more interested in a true counterexample where my concept(which I've not seen in any language before) results in an invalid context....It's obvious to me that the concept is sound within reasonable use bounds.The problem is when such a "idea" is present you get people who are automatically against it for various irrational fears and they won't take any serious look at it to see if it has any merit... If you jump to the conclusion that something is useless without any real thought on it then it obviously is... but the same type of mentality has been used to "prove" just about anything was useless at one time or another. (and if that mentality ruled we'd still be using 640k of memory)I think this is an unfair characterization. The discussion was pretty good and gave the notion a fair shake.I have a very basic question for you and would like a simple answer: In some programming languages, one can do the following type of code: var x; // x is some type of variable that holds data. It's type is not statically defined and can change at run time. x = 3; // x holds some type of number... usually an integer but the language may store all numbers as doubles or even strings. now, suppose we have a program that contains essentially the following: var x; x = 3; Is it possible that the compiler can optimize such code to find the least amount of data to represent x without issue? Yes or no?Yes, and in fact it's already done. Consider: if (expr) { int a; ... } else { int b; ... } In some C implementations, a and b have the same physical address. In some others, they have distinct addresses. This appears to not be related, but it is insofar as a and b have non-overlapping lifetimes.Is this a good thing? Yes or no?It's marginally good - increases stack locality and makes it simpler for a register allocator. (In fact all register allocators do that already, otherwise they'd suck.)(I don't need and don't want any explanation)Too late :o). Andrei
Jul 01 2013
On 7/1/2013 4:30 PM, Andrei Alexandrescu wrote:Yes, and in fact it's already done. Consider: if (expr) { int a; ... } else { int b; ... } In some C implementations, a and b have the same physical address. In some others, they have distinct addresses. This appears to not be related, but it is insofar as a and b have non-overlapping lifetimes.What is happening with (modern) compilers is the "live range" of each variable is computed. A live range is nothing more than a bitmap across the instructions for a function, with a bit set meaning "the variable is in play at this point". The compiler then uses a "tetris" style algorithm to try to fit as many variables as possible into the limited register set, and to use as little stack space as possible. The usual algorithms do not use scoping to determine the live range, but look at actual usage. A variable that, for example, that has no usage is considered 'dead' and is removed. The proposal here neither adds nor subtracts from this.
Jul 01 2013
On Monday, 1 July 2013 at 23:30:19 UTC, Andrei Alexandrescu wrote:On 7/1/13 9:57 AM, JS wrote:Too be honest, your reply seems to be the only one that attempts to discuss exactly what I asked. Nothing more, nothing less. I do realize there was some confusion between what Crystal does and what I'm talking about... I still think the two are confused by some and I'm not sure if anyone quite gets exactly what I am talking about(Which is not re-aliasing any variables, using a sort of variant type(directly at least), or having a multi-variable(e.g., crystal)). Would would be nice is an experimental version of D where would could easily extend the language to try out such concepts to see if they truly are useful and how difficult to implement. e.g., I could attempt to add said "feature", it could be merged with the experimental compiler, those interested can download the compiler and test the feature out... all without negatively affecting D directly. If such features could be implemented dynamically then it would probably be pretty powerful. The example I gave was sort of the reverse. Instead of expanding the type into a supertype we are reducing it. float x; x = 3; x could be stored as a byte which would potentially be an increase in performance. Reducing the type can be pretty dangerous though unless it is verifiable. I'm somewhat convinced that expanding the type is almost always safe(at least in safe code) although not necessarily performant. IMO it makes auto more powerful in most cases but only having a test bed can really say how much.I think there is big confusion in what I'm "suggesting"(it's not a proposal because I don't expect anyone to take the time to prove its validity... and you can't know how useful it could be if you don't have any way to test it out). It's two distinctly different concepts when you allow a "multi-variable" and one that can be "up-typed" by inference(the compiler automatically "up-types").To me the basic notion was very clear from day one. Changing the type of a variable is equivalent with "unaliasing" the existing variable (i.e. destroy it and force it out of the symbol table) and defining an entirely different variable, with its own lifetime. It just so happens it has the same name. It's a reasonable feature to have -- a nice cheat that brings a statically-typed language closer to the look-and-feel of dynamic languages. Saves on names, which is more helpful than one might think. In D things like overloading and implicit conversions would probably make it too confusing to be useful.I'm more interested in a true counterexample where my concept(which I've not seen in any language before) results in an invalid context....It's obvious to me that the concept is sound within reasonable use bounds.The problem is when such a "idea" is present you get people who are automatically against it for various irrational fears and they won't take any serious look at it to see if it has any merit... If you jump to the conclusion that something is useless without any real thought on it then it obviously is... but the same type of mentality has been used to "prove" just about anything was useless at one time or another. (and if that mentality ruled we'd still be using 640k of memory)I think this is an unfair characterization. The discussion was pretty good and gave the notion a fair shake.I have a very basic question for you and would like a simple answer: In some programming languages, one can do the following type of code: var x; // x is some type of variable that holds data. It's type is not statically defined and can change at run time. x = 3; // x holds some type of number... usually an integer but the language may store all numbers as doubles or even strings. now, suppose we have a program that contains essentially the following: var x; x = 3; Is it possible that the compiler can optimize such code to find the least amount of data to represent x without issue? Yes or no?Yes, and in fact it's already done. Consider: if (expr) { int a; ... } else { int b; ... } In some C implementations, a and b have the same physical address. In some others, they have distinct addresses. This appears to not be related, but it is insofar as a and b have non-overlapping lifetimes.Is this a good thing? Yes or no?It's marginally good - increases stack locality and makes it simpler for a register allocator. (In fact all register allocators do that already, otherwise they'd suck.)(I don't need and don't want any explanation)Too late :o). Andrei
Jul 01 2013
On 7/1/13 6:29 PM, JS wrote:Would would be nice is an experimental version of D where would could easily extend the language to try out such concepts to see if they truly are useful and how difficult to implement. e.g., I could attempt to add said "feature", it could be merged with the experimental compiler, those interested can download the compiler and test the feature out... all without negatively affecting D directly. If such features could be implemented dynamically then it would probably be pretty powerful.I don't think such a feature would make it in D, even if the implementation cost was already sunken (i.e. an implementation was already done and one pull request away). Ascribing distinct objects to the same symbol is a very core feature that affects and is affected by everything else. We'd design a lot of D differently if that particular feature were desired, and now the fundamentals of the design are long frozen. For a very simple example, consider: auto a = 2.5; // fine, a is double ... a = 3; By the proposed rule a will become an entirely different variable of type int, and the previous double variable would disappear. But current rules dictate that the type stays double. So we'd either have an unthinkably massive breakage, or we'd patch the language with a million exceptions. Even so! If the feature were bringing amazing power, there may still be a case in its favor. But fundamentally it doesn't bring anything new - it's just alpha renaming; it doesn't enable doing anything that couldn't be done without it. Andrei
Jul 01 2013
On Tuesday, 2 July 2013 at 02:15:09 UTC, Andrei Alexandrescu wrote:On 7/1/13 6:29 PM, JS wrote:No, not under what I am talking about. You can't downgrade a type, only upgrade it. a = 3, a is still a float. Using the concept I am talking about, your example does nothing new. but reverse the numbers: auto a = 3; a = 2.5; and a is now a float, and your logic then becomes correct EXCEPT a is expanded, which is safe. I really don't know how to make it any clearer but I'm not sure if anyone understands what I'm talking about ;/Would would be nice is an experimental version of D where would could easily extend the language to try out such concepts to see if they truly are useful and how difficult to implement. e.g., I could attempt to add said "feature", it could be merged with the experimental compiler, those interested can download the compiler and test the feature out... all without negatively affecting D directly. If such features could be implemented dynamically then it would probably be pretty powerful.I don't think such a feature would make it in D, even if the implementation cost was already sunken (i.e. an implementation was already done and one pull request away). Ascribing distinct objects to the same symbol is a very core feature that affects and is affected by everything else. We'd design a lot of D differently if that particular feature were desired, and now the fundamentals of the design are long frozen. For a very simple example, consider: auto a = 2.5; // fine, a is double ... a = 3;By the proposed rule a will become an entirely different variable of type int, and the previous double variable would disappear. But current rules dictate that the type stays double. So we'd either have an unthinkably massive breakage, or we'd patch the language with a million exceptions. Even so! If the feature were bringing amazing power, there may still be a case in its favor. But fundamentally it doesn't bring anything new - it's just alpha renaming; it doesn't enable doing anything that couldn't be done without it.Expanding a type is always valid because it just consumes more memory. A double can always masquerade as an int without issue because one just wastes 4 bytes. An int can't masquerade as a double because any function think uses it as a double will cause corruption of 4 bytes of memory. (I'm ignoring that a double and int use different cpu instructions. This is irrelevant unless we are hacking stuff up) The simplest example I can give is: auto x = 2; x = 2.5; x IS a double, regardless of the fact that auto x = 2; makes it look like an int BECAUSE that is how auto currently is defined(which might be the confusion). The reason is, that the compiler looked at the scope for all assignments to x and was able to determine automatically that x needed to be a double. I'll give one more way to look at this, that is a sort of inbetween but necessary logical step: We have currently that auto looks at the immediate assignment after it's keyword to determine the type, correct? e.g., auto x = 3; What if we allow auto to look at the first assignment to x, not necessarily the immediate assignment, e.g.: auto x; x = 3; (should be identical to above) or auto x; .... (no assignments to x) x = 3; All this should be semantically equivalent, correct? To me, the last case is more powerful since it is more general. Of course, one could argue that it makes it more difficult to know the type of x but I doubt this would be a huge issue.
Jul 01 2013
On 07/01/2013 07:35 PM, JS wrote:On Tuesday, 2 July 2013 at 02:15:09 UTC, Andrei Alexandrescu wrote:I think I understand. I think I heard either on this or your other thread that function overloading may produce confusing results. Consider the following program: void foo(int i) {} void foo(double d) {} void main() { auto a = 3; foo(a); // Some time later somebody adds the following line: a = 2.5; } If the type of 'a' would suddenly be double from that point on, foo(a) would silently go to a different function. It may be that calling the 'double' overload is the right thing to do but it may as well be that it would be the completely the wrong thing to do. The difference is, today the compiler warns me about the incompatible types. With the proposed feature, the semantics of the program might be different without any warning. Of course one may argue that every line must be added very carefully and the unit tests must be comprehensive, etc. Of course I agree but I am another person who does not see the benefit of this proposal. It is never a chore to modify the type of a variable when the compiler warns me about an incompatibility. Aliauto a = 2.5; // fine, a is double ... a = 3;No, not under what I am talking about. You can't downgrade a type, only upgrade it. a = 3, a is still a float. Using the concept I am talking about, your example does nothing new. but reverse the numbers: auto a = 3; a = 2.5; and a is now a float, and your logic then becomes correct EXCEPT a is expanded, which is safe. I really don't know how to make it any clearer but I'm not sure if anyone understands what I'm talking about ;/
Jul 01 2013
On Tuesday, 2 July 2013 at 03:17:58 UTC, Ali Çehreli wrote:On 07/01/2013 07:35 PM, JS wrote:Yes, basically. If one coded for integers then decided to change it to doubles and was doing some weird stuff then it could completely change the semantics.On Tuesday, 2 July 2013 at 02:15:09 UTC, Andrei Alexandrescuwrote:type, onlyauto a = 2.5; // fine, a is double ... a = 3;No, not under what I am talking about. You can't downgrade aupgrade it. a = 3, a is still a float. Using the concept I amtalkingabout, your example does nothing new. but reverse the numbers: auto a = 3; a = 2.5; and a is now a float, and your logic then becomes correctEXCEPT a isexpanded, which is safe. I really don't know how to make it any clearer but I'm notsure ifanyone understands what I'm talking about ;/I think I understand. I think I heard either on this or your other thread that function overloading may produce confusing results. Consider the following program: void foo(int i) {} void foo(double d) {} void main() { auto a = 3; foo(a); // Some time later somebody adds the following line: a = 2.5; } If the type of 'a' would suddenly be double from that point on, foo(a) would silently go to a different function. It may be that calling the 'double' overload is the right thing to do but it may as well be that it would be the completely the wrong thing to do.The difference is, today the compiler warns me about the incompatible types. With the proposed feature, the semantics of the program might be different without any warning.Yes, this is the "downside" I see. But there doesn't otherwise seem to be any inherent reason why it's a bad idea.Of course one may argue that every line must be added very carefully and the unit tests must be comprehensive, etc. Of course I agree but I am another person who does not see the benefit of this proposal. It is never a chore to modify the type of a variable when the compiler warns me about an incompatibility.No one says that the compiler can't warn you still. One could use a different keyword from the start. Say *autoscope*. If you use that from the get go then you should know full well that strange things are possible(and D can still do strange things without such a "feature"). Although I am of a different mind set than you are in that I like to have more control instead of less. You can't adapt to change if it never happens. Such a feature would, probably in 98% of cases result in something beneficial. Again, after all, if you don't like it don't use it... I do think it would simplify a few things though. Actually, as I mentioned before, there are some use cases where it does reduce code complexity. If one is doing something like this: auto foo(double x) { if(typeof(x) == int) return ""; else return 2; } then they are asking for trouble. auto x; x = foo(1); x = 2.5 or x = 3 result in x becoming a very different type. (and maybe this is essentially the objection of people... but note it's not because of x... auto x = foo(); does the exact same thing. I believe that having the best tool for the job is what is important. But the tools should be available to be used. (This is a general statement, I'm not talking about this "feature") When you need a bazooka you need a bazooka... to not have one really sucks... your pea shooter might do the job 99% of the time and that's fine, that's what should be used. But trying to take out a tank with a pea shooter isn't going to cut it.
Jul 01 2013
On 7/1/13 7:35 PM, JS wrote:On Tuesday, 2 July 2013 at 02:15:09 UTC, Andrei Alexandrescu wrote:You can definitely assume you are being well understood. That's going to break a lot of code because of e.g. calls to overloaded functions in between changes of type. Just drop this. Not only it won't make it into D, it's also not particularly interesting. AndreiOn 7/1/13 6:29 PM, JS wrote:No, not under what I am talking about. You can't downgrade a type, only upgrade it. a = 3, a is still a float. Using the concept I am talking about, your example does nothing new. but reverse the numbers: auto a = 3; a = 2.5; and a is now a float, and your logic then becomes correct EXCEPT a is expanded, which is safe. I really don't know how to make it any clearer but I'm not sure if anyone understands what I'm talking about ;/Would would be nice is an experimental version of D where would could easily extend the language to try out such concepts to see if they truly are useful and how difficult to implement. e.g., I could attempt to add said "feature", it could be merged with the experimental compiler, those interested can download the compiler and test the feature out... all without negatively affecting D directly. If such features could be implemented dynamically then it would probably be pretty powerful.I don't think such a feature would make it in D, even if the implementation cost was already sunken (i.e. an implementation was already done and one pull request away). Ascribing distinct objects to the same symbol is a very core feature that affects and is affected by everything else. We'd design a lot of D differently if that particular feature were desired, and now the fundamentals of the design are long frozen. For a very simple example, consider: auto a = 2.5; // fine, a is double ... a = 3;
Jul 01 2013
On 07/01/2013 06:15 PM, Walter Bright wrote:On 7/1/2013 6:39 AM, Ary Borenszweig wrote:module b; int x; module a; void main(){ int x; { import b; x = 2; } import std.stdio; writeln(x); // prints 0 }D already disallows: int x; { float x; } as an error-prone construct, ...This is not what I am talking about and it seems quite dangerous to have one variable name masquerade as multiple variables.Why dangerous?
Jul 01 2013
On 7/1/2013 10:07 AM, Timon Gehr wrote:module b; int x; module a; void main(){ int x; { import b; x = 2;I'd encourage you to submit an enhancement request that would produce the message: Error: import b.x hides local declaration of x} import std.stdio; writeln(x); // prints 0 }
Jul 01 2013