Re: proposed @noreturn attribute
I didn't look through all of the replies to this thread to check that this hasn't been mentioned yet, but TypeScript uses the 'never' return type for functions that never return. https://www.typescriptlang.org/docs/handbook/basic-types.html#never The type isn't used for any optimisations, it's only used for preventing you from adding lines of code after functions which never return. (Say if they run "forever" or throw exceptions.) I thought it would be worth mentioning how another language handles this currently.
Re: proposed @noreturn attribute
On 07/19/2017 10:32 AM, Timon Gehr wrote: On 19.07.2017 14:13, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types). https://en.wikipedia.org/wiki/Principle_of_explosion Didn't know "false implies anything" comes with such a nice name. Thanks! -- Andrei
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 10:35:37 UTC, Stefan Koch wrote: On Wednesday, 19 July 2017 at 10:24:35 UTC, Marc Schütz wrote: On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. That sounds more like a top type, though, because as you said it can be "anything". A bottom type can not be anything, but only nothing. It's the bottom. Bottom is to Types, as Object is to Classes. Actually, Object should be considered the Top type. All Classes are sub-classes of Object.
Re: proposed @noreturn attribute
On 20.07.2017 00:21, Tobias Müller wrote: Timon Gehrwrote: [...] What I am saying is: in a language with a bottom type, we can create a function: T f(T)(Bottom b){ return b; // assuming b converts to all types implicitly. } Within the function body, b is a value of type Bottom. We use a value of type Bottom to create a value of any type we want. As I understand it, you can create *variables* of type Bottom but not *values*. Correct. b is a variable, not a value, Within the function body, it is. you cannot actually call that function at runtime. Correct.
Re: proposed @noreturn attribute
Timon Gehrwrote: > [...] > What I am saying is: in a language with a bottom type, we can create a > function: > > T f(T)(Bottom b){ > return b; // assuming b converts to all types implicitly. > } > > Within the function body, b is a value of type Bottom. > We use a value of type Bottom to create a value of any type we want. As I understand it, you can create *variables* of type Bottom but not *values*. b is a variable, not a value, you cannot actually call that function at runtime.
Re: proposed @noreturn attribute
On 7/16/2017 6:03 AM, Timon Gehr wrote: pragma(noreturn) is indeed the simpler solution, as it does not interact with anything else. Pragmas are not supposed to change the semantics of the code, they are intended as directions to the compiler, such as: * optimization suggestions * embedding instructions into the object file * sending messages to the user while compiling * instructing the compiler on special name mangling etc. A pragma(noreturn) influences semantics, and so is inappropriate. That's what attributes and types are for.
Re: proposed @noreturn attribute
On 19.07.2017 17:14, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 14:52:28 UTC, Timon Gehr wrote: On 19.07.2017 16:47, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 14:32:24 UTC, Timon Gehr wrote: On 19.07.2017 14:13, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types). https://en.wikipedia.org/wiki/Principle_of_explosion I am aware, but once a statement (and its negation) can be inferred from the same (false) proposition, one isn't reasoning anymore - and more importantly its not useful w.r.t. explaining what the bottom type is. I disagree with both of those statements, but I'm not sure how any of this relates to the true sentence I wrote that you seemed to criticize. The sentence I quoted states you can use a value of type bottom to construct a value of any other type; this means the existence of such a value of type bottom becomes an implicit premise. Not really; see below. As the bottom type is defined as having no values that premise does not hold, i.e. you can infer both "a value of type bottom can be used to construct a value for any other type." and "a value of type bottom cannot be used to construct a value for any other type." from it (principle of explosion, as you quoted). My original criticism was meant to convey that I do not consider the quoted sentence as being helpful w.r.t. explaining what the bottom type is (which the rest of the post I quoted the sentence from did quite well). What I said does not /use/ the principle of explosion; it states it. What I am saying is: in a language with a bottom type, we can create a function: T f(T)(Bottom b){ return b; // assuming b converts to all types implicitly. } Within the function body, b is a value of type Bottom. We use a value of type Bottom to create a value of any type we want. The reason why I included that part of the sentence was: Not all programming languages have subtyping, but all programming languages with a bottom type allow a function of the above type to be constructed. (It's the induction principle for empty algebraic data types.) For any T, the type of !T is T delegate(Bottom), or in different notation: f: ∀a. ⊥ → a. I.e., the type of f is the principle of explosion.
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 14:52:28 UTC, Timon Gehr wrote: On 19.07.2017 16:47, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 14:32:24 UTC, Timon Gehr wrote: On 19.07.2017 14:13, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types). https://en.wikipedia.org/wiki/Principle_of_explosion I am aware, but once a statement (and its negation) can be inferred from the same (false) proposition, one isn't reasoning anymore - and more importantly its not useful w.r.t. explaining what the bottom type is. I disagree with both of those statements, but I'm not sure how any of this relates to the true sentence I wrote that you seemed to criticize. The sentence I quoted states you can use a value of type bottom to construct a value of any other type; this means the existence of such a value of type bottom becomes an implicit premise. As the bottom type is defined as having no values that premise does not hold, i.e. you can infer both "a value of type bottom can be used to construct a value for any other type." and "a value of type bottom cannot be used to construct a value for any other type." from it (principle of explosion, as you quoted). My original criticism was meant to convey that I do not consider the quoted sentence as being helpful w.r.t. explaining what the bottom type is (which the rest of the post I quoted the sentence from did quite well).
Re: proposed @noreturn attribute
On 19.07.2017 16:47, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 14:32:24 UTC, Timon Gehr wrote: On 19.07.2017 14:13, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types). https://en.wikipedia.org/wiki/Principle_of_explosion I am aware, but once a statement (and its negation) can be inferred from the same (false) proposition, one isn't reasoning anymore - and more importantly its not useful w.r.t. explaining what the bottom type is. I disagree with both of those statements, but I'm not sure how any of this relates to the true sentence I wrote that you seemed to criticize.
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 14:32:24 UTC, Timon Gehr wrote: On 19.07.2017 14:13, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types). https://en.wikipedia.org/wiki/Principle_of_explosion I am aware, but once a statement (and its negation) can be inferred from the same (false) proposition, one isn't reasoning anymore - and more importantly its not useful w.r.t. explaining what the bottom type is.
Re: proposed @noreturn attribute
On 19.07.2017 14:13, Moritz Maxeiner wrote: On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types). https://en.wikipedia.org/wiki/Principle_of_explosion
Re: proposed @noreturn attribute
Am Wed, 19 Jul 2017 12:13:40 + schrieb Moritz Maxeiner: > On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: > > a value of type bottom can be used to construct a value for any > > other type. > > AFAIK from type theory, bottom is defined as having no values (so > one can't reason about the relationship of such non-existent > value(s) to values of other types). 2018, Dlang is now an esoteric language. After a long bike-shedding the "bottom type" has been named "nirvana" and assigning it to a variable of any other type signifies intent to give the program a reincarnation. On Posix this was efficiently implemented via fork and exec, Windows implementation is still suffering from bad vibes (bugs). Phobos comes in several flavors now, because it was discovered that one Phobos can never be enough to capture all the worlds paradigms and was considered the main offender to peace on the forums. So there is now an assembly optimized fast Phobos for performance fans without safety nor GC; a type theory Phobos that tries hard to hide the fact that structs have a fixed data layout and makes types first class citizens, but doesn't interop with C at all; an auto-decoding Phobos; and a batteries included Phobos with database drivers, audio, image and GUI bindings. -- Marco
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 11:02:07 UTC, Marc Schütz wrote: On Wednesday, 12 July 2017 at 13:22:46 UTC, Meta wrote: D is not ML or Haskell or Idris. Rust has trod this ground before us and they saw it prudent to not make ! a first-class type. Only to turn around after they realized their mistake: https://doc.rust-lang.org/stable/book/second-edition/ch19-04-advanced-types.html#the-never-type--that-never-returns That page doesn't say anything about passing ! as a type to generic functions (what I'm referring to), but it seems the following code does compile on Rust nightly with the #![feature(never_type)] directive: fn test() {} fn main() { test::(); } So it seems my Rust knowledge is about a year out of date.
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 11:35:47 UTC, Timon Gehr wrote: a value of type bottom can be used to construct a value for any other type. AFAIK from type theory, bottom is defined as having no values (so one can't reason about the relationship of such non-existent value(s) to values of other types).
Re: proposed @noreturn attribute
On 19.07.2017 12:59, Stefan Koch wrote: On Wednesday, 19 July 2017 at 10:44:22 UTC, Timon Gehr wrote: No. Bottom is to types as typeof(null) is to class types. I fear you lost me again :) as far as I understood your previous explanation, every type is a subtype of bottom, is that incorrect ? It is the other way around. Bottom is a subtype of every type / a value of type bottom can be used to construct a value for any other type.
Re: proposed @noreturn attribute
On Wednesday, 12 July 2017 at 13:22:46 UTC, Meta wrote: D is not ML or Haskell or Idris. Rust has trod this ground before us and they saw it prudent to not make ! a first-class type. Only to turn around after they realized their mistake: https://doc.rust-lang.org/stable/book/second-edition/ch19-04-advanced-types.html#the-never-type--that-never-returns
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 10:44:22 UTC, Timon Gehr wrote: No. Bottom is to types as typeof(null) is to class types. I fear you lost me again :) as far as I understood your previous explanation, every type is a subtype of bottom, is that incorrect ?
Re: proposed @noreturn attribute
On 19.07.2017 12:35, Stefan Koch wrote: On Wednesday, 19 July 2017 at 10:24:35 UTC, Marc Schütz wrote: On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. That sounds more like a top type, though, because as you said it can be "anything". A bottom type can not be anything, but only nothing. It's the bottom. Bottom is to Types, as Object is to Classes. No. Bottom is to types as typeof(null) is to class types.
Re: proposed @noreturn attribute
On 19.07.2017 12:24, Marc Schütz wrote: On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. That sounds more like a top type, though, because as you said it can be "anything". A bottom type can not be anything, but only nothing. There is nothing that can be anything, but anything can be top. Natural language has an unfortunate tendency to blur the distinction between dual concepts as it gets more informal.
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 10:24:35 UTC, Marc Schütz wrote: On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. That sounds more like a top type, though, because as you said it can be "anything". A bottom type can not be anything, but only nothing. It's the bottom. Bottom is to Types, as Object is to Classes.
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. That sounds more like a top type, though, because as you said it can be "anything". A bottom type can not be anything, but only nothing.
Re: proposed @noreturn attribute
On 7/18/2017 7:14 PM, Nicholas Wilson wrote: It describe the behaviour of the function: I think it is neither necessary nor a good idea to express it as a type. assert(0) is already accepted as a valid return statement of any type. I can't continue this without being repetitive, so we'll just have to disagree. The backends for DMD, LDC and GDC would not be affected at all by the addition of a bottom type to the front end, and it would be trivial for the glue code to add the noreturn attribute for functions that return the bottom type. Said glue would be unnecessary with an attribute *that already exists*. In the glue code, replace: if (function attribute is 'noreturn') set backend attribute to 'noreturn'; with: if (function return type is 'bottom') set backend attribute to 'noreturn'; set backend function return type to 'void'; and it should be ready to rock :-)
Re: proposed @noreturn attribute
On Wednesday, 19 July 2017 at 01:52:30 UTC, Walter Bright wrote: I know how noreturn attributes work - I implemented them decades ago in DMC and DMC++. They are supported by the DMD optimizer and back end. But they are a hack to the type system, and I suggest an unnecessary one. It describe the behaviour of the function: I think it is neither necessary nor a good idea to express it as a type. assert(0) is already accepted as a valid return statement of any type. The backends for DMD, LDC and GDC would not be affected at all by the addition of a bottom type to the front end, and it would be trivial for the glue code to add the noreturn attribute for functions that return the bottom type. Said glue would be unnecessary with an attribute *that already exists*.
Re: proposed @noreturn attribute
On 7/18/2017 5:54 PM, Nicholas Wilson wrote: There is just something fundamentally wrong with: @noreturn int foo(); I would understand it to mean that if it were to return, foo would return an int but it is undefined behaviour for foo to dynamically return. That's the C++ behavior. I know we are all accustomed to it and hence think it is intuitive, but it isn't. I know I've had a hard time breaking free of this sort of thinking, having been so deeply immersed in C++ for so long. returning a value yet not returning. It smacks of "the language designer(s) are idiots." It winds up complicating things like: auto x = a ? b : foo(); What is the type of x? @noreturn means a special case. A proper bottom type means it is not a special case. int. And if b is of type `T`? It doesn't make sense to have to give a type to something that does not return. (@noreturn functions are usually typed as returning `void` anyway, but that still doesn't make much sense.) I know how noreturn attributes work - I implemented them decades ago in DMC and DMC++. They are supported by the DMD optimizer and back end. But they are a hack to the type system, and I suggest an unnecessary one. The backends for DMD, LDC and GDC would not be affected at all by the addition of a bottom type to the front end, and it would be trivial for the glue code to add the noreturn attribute for functions that return the bottom type.
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 22:03:27 UTC, Walter Bright wrote: The issue here (for me) is to have a type system that matches type systems used in type theory. D already has strong abilities to do type calculus. Instead of inventing our own whackadoodle scheme, one hack at a time, why not match existing type calculus? Then, attempts to do type calculus in D will work as worked out by type theory. Or, we could go with the C++ approach which historically is to add an ad-hoc solution for an existing problem, and then another ad-hoc solution for the whacky effects that turned out to have, rinse, repeat. (Look at all the different ways to do type deduction, a horrifying consequence. Or function overloading, which started with complex special cases, then changed to partial ordering for special cases.) There is just something fundamentally wrong with: @noreturn int foo(); I would understand it to mean that if it were to return, foo would return an int but it is undefined behaviour for foo to dynamically return. returning a value yet not returning. It smacks of "the language designer(s) are idiots." It winds up complicating things like: auto x = a ? b : foo(); What is the type of x? @noreturn means a special case. A proper bottom type means it is not a special case. int. @noreturn need not pollute the type, given the use cases for @noreturn. Namely to document that the function does not dynamically return and aid the compiler in optimisation (are there any other uses?). `assert(0);` is already accepted in the front end as an acceptable return "value" for any type e.g. in Bar foo(int x) { foreach (e; data[]) if (e.x == x) return e; assert(0); } The language semantics and compiler internals should be simpler and cleaner by using accepted type theory. Not for LDC or GDC. They already have the ability to signal to their backends that a function does not dynamically return. as I have posted before, one can do (in core.attribute), enum __noreturn; version(LDC) { import ldc.attributes : llvmAttr; alias noreturn = AliasSeq!(llvmAttr("noreturn"),__noreturn); } else version(GNU) { import gcc.attribute : llvmAttr; alias noreturn = AliasSeq!(attribute("noreturn"),__noreturn); } else // DMD { alias noreturn = __noreturn; } for a complete implementation for LDC and GDC, and DMD can do whatever it needs to with the presence of __noreturn, including fronted semantic analysis.
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 22:03:27 UTC, Walter Bright wrote: On 7/17/2017 4:26 PM, H. S. Teoh via Digitalmars-d wrote: But the point is that so much time and effort is being spent on discussing and designing a feature that you have admitted yourself to be "rarely used". As a disinterested bystander I find it somewhat amusing (and sad) to see so much over-engineering of an overly-complex system involving a new basic type in the language, which in turn entails all sorts of corner cases in how it will interact with existing types and constructs, not to mention the implementation complexities that will be involved to pull it off -- all for what? Just to be able to say "function F doesn't return". Seems like disproportionate effort for only marginal returns (har har). The issue here (for me) is to have a type system that matches type systems used in type theory. D already has strong abilities to do type calculus. Instead of inventing our own whackadoodle scheme, one hack at a time, why not match existing type calculus? Then, attempts to do type calculus in D will work as worked out by type theory. Or, we could go with the C++ approach which historically is to add an ad-hoc solution for an existing problem, and then another ad-hoc solution for the whacky effects that turned out to have, rinse, repeat. (Look at all the different ways to do type deduction, a horrifying consequence. Or function overloading, which started with complex special cases, then changed to partial ordering for special cases.) [...] Agreed. Discovered vs invented as Philip Wadler classifies the two approaches in his talk: https://www.youtube.com/watch?v=IOiZatlZtGU, which I highly recommend watching.
Re: proposed @noreturn attribute
On 18.07.2017 23:35, Moritz Maxeiner wrote: Could you explain why `return foo();` is even legal for a `void foo() {}`? Because the ad-hoc decision to make void a type that is not really a type leads to unnecessary friction, and this exceptional rule removes the friction in one common special case. I wasn't aware of it before and the fact that you can (syntactically) return the non-existent return value of `foo` raises cognitive dissonance flags for me. I imagine there's a type system reason? There should be. foo's return type could be a unit type, with just one value. Then foo does have a return value, but it is always the same and so does not need to be explicitly tracked.
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 21:45:27 UTC, Adam D. Ruppe wrote: On Tuesday, 18 July 2017 at 21:35:21 UTC, Moritz Maxeiner wrote: Could you explain why `return foo();` is even legal for a `void foo() {}`? Suppose you are writing a template function that forwards: auto forward(alias fun, T...)(T args) { return fun(args); } It just saves you from having to static if(fun returns void). That's a good pragmatic (syntactic sugar) reason, thanks.
Re: proposed @noreturn attribute
On 7/17/2017 4:26 PM, H. S. Teoh via Digitalmars-d wrote: But the point is that so much time and effort is being spent on discussing and designing a feature that you have admitted yourself to be "rarely used". As a disinterested bystander I find it somewhat amusing (and sad) to see so much over-engineering of an overly-complex system involving a new basic type in the language, which in turn entails all sorts of corner cases in how it will interact with existing types and constructs, not to mention the implementation complexities that will be involved to pull it off -- all for what? Just to be able to say "function F doesn't return". Seems like disproportionate effort for only marginal returns (har har). The issue here (for me) is to have a type system that matches type systems used in type theory. D already has strong abilities to do type calculus. Instead of inventing our own whackadoodle scheme, one hack at a time, why not match existing type calculus? Then, attempts to do type calculus in D will work as worked out by type theory. Or, we could go with the C++ approach which historically is to add an ad-hoc solution for an existing problem, and then another ad-hoc solution for the whacky effects that turned out to have, rinse, repeat. (Look at all the different ways to do type deduction, a horrifying consequence. Or function overloading, which started with complex special cases, then changed to partial ordering for special cases.) There is just something fundamentally wrong with: @noreturn int foo(); returning a value yet not returning. It smacks of "the language designer(s) are idiots." It winds up complicating things like: auto x = a ? b : foo(); What is the type of x? @noreturn means a special case. A proper bottom type means it is not a special case. I recall that Rust initially did @noreturn as a special case, and later replaced that with a bottom type and integrated it into the type system. I understand that this had a positive ripple effect, such as reducing special cases in user generic code. Noreturn functions are just a happy fallout of doing this correctly in the first place. The language semantics and compiler internals should be simpler and cleaner by using accepted type theory.
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 21:35:21 UTC, Moritz Maxeiner wrote: Could you explain why `return foo();` is even legal for a `void foo() {}`? Suppose you are writing a template function that forwards: auto forward(alias fun, T...)(T args) { return fun(args); } It just saves you from having to static if(fun returns void).
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 20:49:56 UTC, Timon Gehr wrote: On 18.07.2017 20:46, Yuxuan Shui wrote: On Tuesday, 18 July 2017 at 15:26:59 UTC, Timon Gehr wrote: On 18.07.2017 14:19, Stefan Koch wrote: [...] D has a C-inspired first-order type system, so it is not necessarily crucial to have it in D. (The reason I got involved in this thread is that it was proposed to add Bottom as a type that is not really a type; 'void' is annoying enough as the 'null' of types. We don't really need another one of those.) [...] What about void? You can't have a value of type void, but it is not empty either. For example, this means that the following transformation is not always valid: return foo(); Could you explain why `return foo();` is even legal for a `void foo() {}`? I wasn't aware of it before and the fact that you can (syntactically) return the non-existent return value of `foo` raises cognitive dissonance flags for me. I imagine there's a type system reason?
Re: proposed @noreturn attribute
On 18.07.2017 20:46, Yuxuan Shui wrote: On Tuesday, 18 July 2017 at 15:26:59 UTC, Timon Gehr wrote: On 18.07.2017 14:19, Stefan Koch wrote: [...] D has a C-inspired first-order type system, so it is not necessarily crucial to have it in D. (The reason I got involved in this thread is that it was proposed to add Bottom as a type that is not really a type; 'void' is annoying enough as the 'null' of types. We don't really need another one of those.) [...] What about void? You can't have a value of type void, but it is not empty either. For example, this means that the following transformation is not always valid: return foo(); <-> auto x = foo(); return x;
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 15:26:59 UTC, Timon Gehr wrote: On 18.07.2017 14:19, Stefan Koch wrote: [...] D has a C-inspired first-order type system, so it is not necessarily crucial to have it in D. (The reason I got involved in this thread is that it was proposed to add Bottom as a type that is not really a type; 'void' is annoying enough as the 'null' of types. We don't really need another one of those.) [...] What about void?
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 18:54:37 UTC, H. S. Teoh wrote: On Mon, Jul 17, 2017 at 02:10:27PM -0400, Andrei Alexandrescu via Digitalmars-d wrote: [...] [...] IMO, the observations "used rarely" and "attention-seeking notation" are better satisfied by an attribute named @noreturn than some strange, convoluted, arcane invocation like `typeof(assert(0))`. Because: [...] object.d: alias noreturn = typeof(assert(0)); Atila
Re: proposed @noreturn attribute
On 18.07.2017 14:19, Stefan Koch wrote: On Tuesday, 18 July 2017 at 12:15:06 UTC, Timon Gehr wrote: On 18.07.2017 12:17, John Colvin wrote: Better to just not define it. That's not an option. Bottom is a subtype of all types. It cannot remove members, even static ones. Timon, how important is it to actually have bottom ? D has a C-inspired first-order type system, so it is not necessarily crucial to have it in D. (The reason I got involved in this thread is that it was proposed to add Bottom as a type that is not really a type; 'void' is annoying enough as the 'null' of types. We don't really need another one of those.) Bottom is the most principled way to encode noreturn (but the D type system does not have a tradition of being very principled, so introducing it has a cost that does not really exist the same way in more orthogonal designs: it falls out of them naturally). If you have a very expressive type system, it is important to have empty types, because there you cannot actually decide algorithmically whether any given type is in fact empty. Another reason why one might want an empty type is that it is the neutral element for disjoint union (up to isomorphism). (But D does not have those built-in.) ... and what does it actually represent ? It's a type that has no instances. If I say int foo(); this means foo returns one of {0,1,-1,2,-2,3,-3,...,int.max,int.min}. If I say Bottom foo(); this means foo returns one of {}. I.e., there is no value which foo might return. Hence it cannot return. It can be argued that it is a bit silly to say: int foo()@noreturn; I.e., this function returns one of {0,1,-1,2,-2,3,-3,...,int.max,int.min}, but actually, it does not return anything. The first piece of information is redundant. The closure of all possible types ? like auto but if auto where not replaced ? Your intuition is correct. In a higher-order type system, you can have: (∀a. a) foo(); This says that foo returns a value that has any type you wish it to have. Of course, there is no single value that has all types (ignoring e.g. full OO languages that have null references), hence we have no way to actually construct a value satisfying the constraints, so (∀a. a) is an empty type. In languages with subtyping, Bottom is often just a subtype of all other types. (The name "Bottom" stems from here: https://en.wikipedia.org/wiki/Lattice_(order)#Bounded_lattice . The bounded lattice in question is the subtyping lattice, where A ≤ B means A is a subtype of B.) One reason why it is nice to have a bounded subtyping lattice is that then, you can express subtyping constraints uniformly: A≤B does not constraint B if A is Bottom, and it does not constrain A if B is Top.
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 12:15:06 UTC, Timon Gehr wrote: On 18.07.2017 12:17, John Colvin wrote: Better to just not define it. That's not an option. Bottom is a subtype of all types. It cannot remove members, even static ones. Timon, how important is it to actually have bottom ? ... and what does it actually represent ? The closure of all possible types ? like auto but if auto where not replaced ?
Re: proposed @noreturn attribute
On 18.07.2017 12:17, John Colvin wrote: Better to just not define it. That's not an option. Bottom is a subtype of all types. It cannot remove members, even static ones.
Re: proposed @noreturn attribute
On Tuesday, 18 July 2017 at 10:17:17 UTC, John Colvin wrote: how do I store the type "int" in memory? new Type(TYENUM.Tint32); :o)
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 23:01:40 UTC, Walter Bright wrote: On 7/16/2017 5:41 AM, Timon Gehr wrote: struct S{ T x; Bottom everything; } turns the entire struct into an empty type. It is therefore most natural to say that Bottom.sizeof == ∞. (It's the only choice for which S.sizeof == Bottom.sizeof.) Another way to think about it: If something of type A* converts to something of type B* without problems, then one would expect B.sizeof <= A.sizeof. This would imply that Bottom.sizeof >= size_t.max. (Because Bottom* converts to all other pointer types.) One small issue is that one needs to avoid overflow for the size of a struct that has multiple fields where one of them is of type Bottom. But if Bottom does not exist, then S doesn't exist either, and hence the < size relationship has no meaning. (Reminds me of divide by 0 discussions in calculus class.) Strictly speaking it just shouldn't have a sizeof, because sizeof is shorthand for "size of an instance of" (types don't really have sizes, how do I store the type "int" in memory?) and Bottom has no instances. Infinity - or the next best applicable thing size_t.max - is a reasonable standin for an invalid value, except that people will do silly things like `auto paddedSpace = (ReturnType!foo).sizeof + 1;` and then you're in trouble. Better to just not define it. Is there some magic that can be done where all code that makes reference to an instance of Bottom just isn't compiled? I.e. if there happens to be a situation where a function returns Bottom then all code that touches that return type is just ignored?
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 18:10:27 UTC, Andrei Alexandrescu wrote: On 7/17/17 11:39 AM, Olivier FAURE wrote: I'd really prefer if you avoided the whole `typeof(assert(0))` thing. First off, it's way too verbose for a simple concept. Noted, thanks. I won't debate this much but for now I disagree. Fair enough.
Re: proposed @noreturn attribute
On 18.07.2017 03:06, Walter Bright wrote: On 7/17/2017 5:13 PM, Timon Gehr wrote: (Reminds me of divide by 0 discussions in calculus class.) The reason division by 0 is left undefined is that instead saying 1/0 = ∞ introduces a new number ∞ that does not play nice with the axioms of a complete ordered field. The question for instance size is based on the wrong assumption that there is such an instance. It is true none the less that ∞ is the most natural answer to this question, as if you have multiple answers for instance size, you'd take the supremum. Of course, size_t does not contain ∞. Infinity makes sense for 1/0, but I don't see how that automatically transfers to size_t. It does not. The reasoning is unrelated.
Re: proposed @noreturn attribute
On 7/17/2017 5:13 PM, Timon Gehr wrote: (Reminds me of divide by 0 discussions in calculus class.) The reason division by 0 is left undefined is that instead saying 1/0 = ∞ introduces a new number ∞ that does not play nice with the axioms of a complete ordered field. The question for instance size is based on the wrong assumption that there is such an instance. It is true none the less that ∞ is the most natural answer to this question, as if you have multiple answers for instance size, you'd take the supremum. Of course, size_t does not contain ∞. Infinity makes sense for 1/0, but I don't see how that automatically transfers to size_t.
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 18:54:37 UTC, H. S. Teoh wrote: IMO, the observations "used rarely" and "attention-seeking notation" are better satisfied by an attribute named @noreturn than some strange, convoluted, arcane invocation like `typeof(assert(0))`. Because: (1) "used rarely" means it should be as non-intrusive as possible as far as the language is concerned -- we should not spend a lot of language real estate on something that's rarely used, nor should it be something complicated to implement, and/or introduces tricky corner cases that we're likely to get wrong on first attempt. A @noreturn attribute is non-intrusive -- doesn't interact with anything else in the language, easy to implement -- has no tricky corner cases. (2) "attention-seeking": an arcane invocation like `typeof(assert(0))` is harder to parse and therefore more likely to invite people to just gloss over it as "incomprehensible gibberish that I'll just ignore unless I have to look further", than catch people's attention. Whereas an annotation like `@noreturn` is immediately obvious by its very presence, with a name that instantly tells you what it does while it still holds your attention. I see `typeof(assert(0))` as the same kind of over-engineering of something trivially solved and relatively unimportant ("rarely used") that has unfortunately plagued C++ design and led C++ to become the mess it is today. It's sad to see D start down the same path... T (3) LDC and GDC already have an implementation in the form of an attribute so we can just have an AliasSeq of the front end recognised attribute and the one for GDC and LDC (assuming my attributes DIP goes through).
Re: proposed @noreturn attribute
On 7/17/2017 5:06 PM, Seb via Digitalmars-d wrote: I can't agree more. This is textbook procrastination and bike-shedding [1]! There are dozens of open regressions that could have fixed or great, stalled PRs that could have been reviewed. In fact if only PRs would be as heartily reviewed as the discussion here, things like the fact that DMD leaks all symbols when imported selectively [2] would have been uncovered earlier. [1] https://en.wikipedia.org/wiki/Law_of_triviality [2] https://github.com/dlang/phobos/pull/5584#issuecomment-314910297 Semi-valid, but fungability of time and effort>.
Re: proposed @noreturn attribute
On 18.07.2017 01:01, Walter Bright wrote: ... But if Bottom does not exist, then S doesn't exist either, and hence the < size relationship has no meaning. ... Both Bottom and S exist, but they have no instances. (Reminds me of divide by 0 discussions in calculus class.) The reason division by 0 is left undefined is that instead saying 1/0 = ∞ introduces a new number ∞ that does not play nice with the axioms of a complete ordered field. The question for instance size is based on the wrong assumption that there is such an instance. It is true none the less that ∞ is the most natural answer to this question, as if you have multiple answers for instance size, you'd take the supremum. Of course, size_t does not contain ∞.
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 23:26:18 UTC, H. S. Teoh wrote: Actually, I don't really care enough about this issue to want it to be implemented one way or another, as long as there is *some* way to annotate a non-returning function. But the point is that so much time and effort is being spent on discussing and designing a feature that you have admitted yourself to be "rarely used". As a disinterested bystander I find it somewhat amusing (and sad) to see so much over-engineering of an overly-complex system involving a new basic type in the language, which in turn entails all sorts of corner cases in how it will interact with existing types and constructs, not to mention the implementation complexities that will be involved to pull it off -- all for what? Just to be able to say "function F doesn't return". Seems like disproportionate effort for only marginal returns (har har). I can't agree more. This is textbook procrastination and bike-shedding [1]! There are dozens of open regressions that could have fixed or great, stalled PRs that could have been reviewed. In fact if only PRs would be as heartily reviewed as the discussion here, things like the fact that DMD leaks all symbols when imported selectively [2] would have been uncovered earlier. [1] https://en.wikipedia.org/wiki/Law_of_triviality [2] https://github.com/dlang/phobos/pull/5584#issuecomment-314910297
Re: proposed @noreturn attribute
On Mon, Jul 17, 2017 at 06:42:02PM -0400, Andrei Alexandrescu via Digitalmars-d wrote: > On 7/17/17 2:54 PM, H. S. Teoh via Digitalmars-d wrote: > > I see `typeof(assert(0))` as the same kind of over-engineering of > > something trivially solved and relatively unimportant ("rarely > > used") that has unfortunately plagued C++ design and led C++ to > > become the mess it is today. It's sad to see D start down the same > > path... > > There is no reason to over-react seeing as the option of adding a name > is easy and always available; removing it not so much. This makes > taking options in language design highly asymmetrical. Having the type > available as an actual expression brings good options on the table > because people can return those on unreachable paths etc. -- Andrei Actually, I don't really care enough about this issue to want it to be implemented one way or another, as long as there is *some* way to annotate a non-returning function. But the point is that so much time and effort is being spent on discussing and designing a feature that you have admitted yourself to be "rarely used". As a disinterested bystander I find it somewhat amusing (and sad) to see so much over-engineering of an overly-complex system involving a new basic type in the language, which in turn entails all sorts of corner cases in how it will interact with existing types and constructs, not to mention the implementation complexities that will be involved to pull it off -- all for what? Just to be able to say "function F doesn't return". Seems like disproportionate effort for only marginal returns (har har). T -- Those who don't understand D are condemned to reinvent it, poorly. -- Daniel N
Re: proposed @noreturn attribute
On 7/16/2017 5:41 AM, Timon Gehr wrote: struct S{ T x; Bottom everything; } turns the entire struct into an empty type. It is therefore most natural to say that Bottom.sizeof == ∞. (It's the only choice for which S.sizeof == Bottom.sizeof.) Another way to think about it: If something of type A* converts to something of type B* without problems, then one would expect B.sizeof <= A.sizeof. This would imply that Bottom.sizeof >= size_t.max. (Because Bottom* converts to all other pointer types.) One small issue is that one needs to avoid overflow for the size of a struct that has multiple fields where one of them is of type Bottom. But if Bottom does not exist, then S doesn't exist either, and hence the < size relationship has no meaning. (Reminds me of divide by 0 discussions in calculus class.)
Re: proposed @noreturn attribute
On 7/16/2017 1:15 PM, Timon Gehr wrote: In this case, Bottom.sizeof is a value of type Bottom, which must not exist. T.sizeof is a value of type size_t, not type T.
Re: proposed @noreturn attribute
On 7/17/17 2:54 PM, H. S. Teoh via Digitalmars-d wrote: I see `typeof(assert(0))` as the same kind of over-engineering of something trivially solved and relatively unimportant ("rarely used") that has unfortunately plagued C++ design and led C++ to become the mess it is today. It's sad to see D start down the same path... There is no reason to over-react seeing as the option of adding a name is easy and always available; removing it not so much. This makes taking options in language design highly asymmetrical. Having the type available as an actual expression brings good options on the table because people can return those on unreachable paths etc. -- Andrei
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 18:54:37 UTC, H. S. Teoh wrote: On Mon, Jul 17, 2017 at 02:10:27PM -0400, Andrei Alexandrescu via Digitalmars-d wrote: On 7/17/17 11:39 AM, Olivier FAURE wrote: > I'd really prefer if you avoided the whole > `typeof(assert(0))` > thing. > > First off, it's way too verbose for a simple concept. Noted, thanks. I won't debate this much but for now I disagree. The "no return" type has several particular properties that set it aside (e.g. it's impossible to implement as a library, does things no other types do, etc). It's also used rarely. Therefore it stands to reason to consider an attention-seeking notation for it. [...] IMO, the observations "used rarely" and "attention-seeking notation" are better satisfied by an attribute named @noreturn than some strange, convoluted, arcane invocation like `typeof(assert(0))`. Because: (1) "used rarely" means it should be as non-intrusive as possible as far as the language is concerned -- we should not spend a lot of language real estate on something that's rarely used, nor should it be something complicated to implement, and/or introduces tricky corner cases that we're likely to get wrong on first attempt. A @noreturn attribute is non-intrusive -- doesn't interact with anything else in the language, easy to implement -- has no tricky corner cases. (2) "attention-seeking": an arcane invocation like `typeof(assert(0))` is harder to parse and therefore more likely to invite people to just gloss over it as "incomprehensible gibberish that I'll just ignore unless I have to look further", than catch people's attention. Whereas an annotation like `@noreturn` is immediately obvious by its very presence, with a name that instantly tells you what it does while it still holds your attention. I see `typeof(assert(0))` as the same kind of over-engineering of something trivially solved and relatively unimportant ("rarely used") that has unfortunately plagued C++ design and led C++ to become the mess it is today. It's sad to see D start down the same path... T +1000! You've said it all!
Re: proposed @noreturn attribute
On Mon, Jul 17, 2017 at 02:10:27PM -0400, Andrei Alexandrescu via Digitalmars-d wrote: > On 7/17/17 11:39 AM, Olivier FAURE wrote: > > I'd really prefer if you avoided the whole `typeof(assert(0))` > > thing. > > > > First off, it's way too verbose for a simple concept. > > Noted, thanks. I won't debate this much but for now I disagree. The > "no return" type has several particular properties that set it aside > (e.g. it's impossible to implement as a library, does things no other > types do, etc). It's also used rarely. Therefore it stands to reason > to consider an attention-seeking notation for it. [...] IMO, the observations "used rarely" and "attention-seeking notation" are better satisfied by an attribute named @noreturn than some strange, convoluted, arcane invocation like `typeof(assert(0))`. Because: (1) "used rarely" means it should be as non-intrusive as possible as far as the language is concerned -- we should not spend a lot of language real estate on something that's rarely used, nor should it be something complicated to implement, and/or introduces tricky corner cases that we're likely to get wrong on first attempt. A @noreturn attribute is non-intrusive -- doesn't interact with anything else in the language, easy to implement -- has no tricky corner cases. (2) "attention-seeking": an arcane invocation like `typeof(assert(0))` is harder to parse and therefore more likely to invite people to just gloss over it as "incomprehensible gibberish that I'll just ignore unless I have to look further", than catch people's attention. Whereas an annotation like `@noreturn` is immediately obvious by its very presence, with a name that instantly tells you what it does while it still holds your attention. I see `typeof(assert(0))` as the same kind of over-engineering of something trivially solved and relatively unimportant ("rarely used") that has unfortunately plagued C++ design and led C++ to become the mess it is today. It's sad to see D start down the same path... T -- I see that you JS got Bach.
Re: proposed @noreturn attribute
On 7/17/17 11:39 AM, Olivier FAURE wrote: I'd really prefer if you avoided the whole `typeof(assert(0))` thing. First off, it's way too verbose for a simple concept. Noted, thanks. I won't debate this much but for now I disagree. The "no return" type has several particular properties that set it aside (e.g. it's impossible to implement as a library, does things no other types do, etc). It's also used rarely. Therefore it stands to reason to consider an attention-seeking notation for it. The upside of this is we can always add an alias to give the type a name if we so wish. For now I'd want to experiment with using typeof as notation. Andrei
Re: proposed @noreturn attribute
On Monday, 17 July 2017 at 15:39:30 UTC, Olivier FAURE wrote: On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references. I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code. You're on to something here. Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. The latter is a mere consequence of the former. I'd really prefer if you avoided the whole `typeof(assert(0))` thing. First off, it's way too verbose for a simple concept. In general, code is much more readable when you can read functions as `Type functionName(args)`, rather than template-style `expr(valueof!(thing + otherThing).typeof) functionName(args)`, so I think it would be better not to encourage adding more expressions as return types. I think the following: noreturn_t logThenQuit(string message) is much more readable and obvious (especially to a beginner) than: typeof(*null) logThenQuit(string message) Of course, you could implement typeof(*null); and also add noreturn_t as an alias; it might be a good compromise; I'd still dislike it because it encourages people to use the verbose hard to understand version. The second reason I don't like it is that I feel it's just trying to be clever for the sake of cleverness. I don't think we need a language feature that perfectly matches the idea of not returning from a function on a deep, philosophical level; we just need a way to tell the type system "Hey, this function doesn't return!". I don't think `typeof(*null)`, or `typeof(assert(0))` brings any advantage in term of real life user code, and I don't think it's worth the confused users that would look at code and go "Uh? What is the type of *null?" or "I thought assert was void! What would you get the type of assert()?". Yes, this!
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 20:44:13 UTC, Andrei Alexandrescu wrote: An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references. I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code. You're on to something here. Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. The latter is a mere consequence of the former. I'd really prefer if you avoided the whole `typeof(assert(0))` thing. First off, it's way too verbose for a simple concept. In general, code is much more readable when you can read functions as `Type functionName(args)`, rather than template-style `expr(valueof!(thing + otherThing).typeof) functionName(args)`, so I think it would be better not to encourage adding more expressions as return types. I think the following: noreturn_t logThenQuit(string message) is much more readable and obvious (especially to a beginner) than: typeof(*null) logThenQuit(string message) Of course, you could implement typeof(*null); and also add noreturn_t as an alias; it might be a good compromise; I'd still dislike it because it encourages people to use the verbose hard to understand version. The second reason I don't like it is that I feel it's just trying to be clever for the sake of cleverness. I don't think we need a language feature that perfectly matches the idea of not returning from a function on a deep, philosophical level; we just need a way to tell the type system "Hey, this function doesn't return!". I don't think `typeof(*null)`, or `typeof(assert(0))` brings any advantage in term of real life user code, and I don't think it's worth the confused users that would look at code and go "Uh? What is the type of *null?" or "I thought assert was void! What would you get the type of assert()?".
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 20:15:11 UTC, Timon Gehr wrote: On 16.07.2017 21:49, Guillaume Boucher wrote: On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote: It is therefore most natural to say that Bottom.sizeof == ∞. True, but size_t.max doesn't have the properties of ∞. The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom). In this case, Bottom.sizeof is a value of type Bottom, which must not exist. It doesn't exist during runtime, but there's no problem to just generate assert(0) where it's used. I think my interpretation produces the least exceptions, but if you have a better idea go ahead.
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 20:04:25 UTC, Timon Gehr wrote: The issue isn't purism, it is type safety. If you create an EvolvedPenguin, upcast it to a Penguin and call the fly method you get UB. So noreturn would indeed need to enforce that all overrides are also noreturn. I see it as some kind of weak guarantee, where the compiler can assume noreturn only if he knows there are no subtypes involved (e.g. if he's applying devirtualization). Automatically inheriting the attribute could break existing code (especially if it's inferred).
Re: proposed @noreturn attribute
On 07/13/2017 01:25 PM, Timon Gehr wrote: On Wednesday, 12 July 2017 at 14:23:15 UTC, Andrei Alexandrescu wrote: On 07/12/2017 05:32 AM, Timon Gehr wrote: On 09.07.2017 23:45, Meta wrote: ... Another case that we should probably just statically disallow: ... > This obviously doesn't make any sense anyway ... > I don't see a reason for us to ever need to do that Sorry, but this thinking has no place in type system design. This is precisely how you create a convoluted nonsensical mess. Timon, I think you're very well positioned to author a DIP on this. Getting through acceptance on your static foreach DIP seems to not require a lot of extra work. ... I might do that, however there are a couple of open questions (see below). Sorry missed those... let's see: It's perfectly fine to have a type of types which is its own type, especially if you allow non-termination. I'm saying the D notion of subtyping is a bit messy because memory layout matters and subtyping and implicit conversion are not the same thing. Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. typeof(assert(0))* and typeof(assert(0))[] will hence be subtypes of all other pointer and array types respectively. Wow. Cool! An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references. I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code. You're on to something here. Perhaps we go the inverse route and define the bottom type as typeof(*null). Would that simplify matters? There is some good consistency about it: null: a pointer to anything. But can't be dereferenced. *null: well, therefore... anything. But can't be created. The latter is a mere consequence of the former. I think the DIP should introduce conversion from the start, as conversion is easy to support. It is simple to support in the front end and the code gen for it is literally to emit nothing. Fantastic. Please kick it off. Thanks!! Andrei
Re: proposed @noreturn attribute
On 07/16/2017 04:15 PM, Timon Gehr wrote: On 16.07.2017 21:49, Guillaume Boucher wrote: On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote: It is therefore most natural to say that Bottom.sizeof == ∞. True, but size_t.max doesn't have the properties of ∞. The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom). In this case, Bottom.sizeof is a value of type Bottom, which must not exist. Yah that's not workable. Generally the fewer odd exceptions the better, lest all generic code going forward will have to account for those. Timon, since you got your first DIP approved, now is the time to keep the momentum going with a new one! Andrei
Re: proposed @noreturn attribute
On 16.07.2017 21:49, Guillaume Boucher wrote: On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote: It is therefore most natural to say that Bottom.sizeof == ∞. True, but size_t.max doesn't have the properties of ∞. The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom). In this case, Bottom.sizeof is a value of type Bottom, which must not exist.
Re: proposed @noreturn attribute
On 16.07.2017 21:49, Guillaume Boucher wrote: I'd say a function with return type Bottom can override any function in the base class. That solves the "Penguin : Bird" step, but not "EvolvedPenguin : Penguin" (which can fly). Andrei argues that my example don't comply with a puristic understanding of inheritance. Maybe that's enough of a reason to not optimize such use cases, but it still shows that pragma(noreturn) is somehow stronger than Bottom. The issue isn't purism, it is type safety. If you create an EvolvedPenguin, upcast it to a Penguin and call the fly method you get UB. So noreturn would indeed need to enforce that all overrides are also noreturn.
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 12:41:06 UTC, Timon Gehr wrote: It is therefore most natural to say that Bottom.sizeof == ∞. True, but size_t.max doesn't have the properties of ∞. The only sane choice to me seems to be a value of type Bottom, i.e. is(typeof(Bottom.sizeof) == Bottom).
Re: proposed @noreturn attribute
On Sunday, 16 July 2017 at 13:03:40 UTC, Timon Gehr wrote: I don't think that's true. A Bottom type does not cover all use cases of @noreturn/@pragma(noreturn). ... I think it does, but it is a significantly more invasive language change. The best you can hope for is that any code with pragma(noreturn) can be rewritten into functionally equivalent code that uses Bottom and gives the same hints to the optimizer. pragma(noreturn) can be inferred implicitly which makes it more impactful in practice. I'd say a function with return type Bottom can override any function in the base class. That solves the "Penguin : Bird" step, but not "EvolvedPenguin : Penguin" (which can fly). Andrei argues that my example don't comply with a puristic understanding of inheritance. Maybe that's enough of a reason to not optimize such use cases, but it still shows that pragma(noreturn) is somehow stronger than Bottom. pragma(noreturn) is indeed the simpler solution, as it does not interact with anything else. The fact that template constraints in some cases need to be aware of the existence of Bottom in order to work for Bottom is clearly a negative property of this solution in the context of D. Yes, basically this. You can return 'auto' instead of U. Then the return type will be inferred either as U or Bottom. Sure there are workarounds. Also here: auto deref(T)(ref T* x) { return deref(*x); } ref T deref(T)(ref T x) if (!isPointer!T) { return x; } But when every small function needs a rewrite, something seems off.
Re: proposed @noreturn attribute
On 14.07.2017 17:39, Guillaume Boucher wrote: On Monday, 10 July 2017 at 04:02:59 UTC, Nicholas Wilson wrote: 1)@noreturn 2)@disable(return) 3)none w.r.t optimisation assuming both 1 & 3 impact DMD equally [...] I don't think that's true. A Bottom type does not cover all use cases of @noreturn/@pragma(noreturn). ... I think it does, but it is a significantly more invasive language change. Example 1: Polymorphism class Bird { void fly() { ... } }; class Penguin : Bird { override void fly() @pragma(noreturn) { assert(0); } }; class EvolvedPenguin : Penguin { override void fly() { ... } }; There's no way to encode that information in a return type. ... I'd say a function with return type Bottom can override any function in the base class. Example 2: Compile-time polymorphism Same as above, except during compile time. While it looks ok in theory (just return Bottom, and everything is alright), it seems very tricky to get right. Example from checkedint.d: auto r = hook.hookOpUnary!op(payload); return Checked!(typeof(r), Hook)(r); Let's say the hook refuses to perform hookOpUnary, so r is Bottom. Unfortunately, Checked!(Bottom, Hook)(r) doesn't compile (because "if (isIntegral!T || is(T == Checked!(U, H), U, H))" fails). While Bottom may be substituted into all expressions (which doesn't seem easy anyway), it for sure can't be inserted as any template argument. As seen before, Checked is not Bottom-proof. I would think that most templates are not Bottom-proof and making them Bottom-proof seems quite a bit of work. ... The problem for this example is that the current implementation of isIntegral would return false for Bottom. With @pragma(noreturn) that situation would be no problem. ... pragma(noreturn) is indeed the simpler solution, as it does not interact with anything else. The fact that template constraints in some cases need to be aware of the existence of Bottom in order to work for Bottom is clearly a negative property of this solution in the context of D. Example 3: Unreachable statements/Implicit noreturn inference As pointed out by Steven Schveighoffer, the current unreachability errors should probably be removed in generic code. If we do that, then generic functions can be @pragma(noreturn) if certain conditions are met. A compiler can easily figure that out, but writing it inside static ifs could be almost impossible. Assume we have a hook to Checked that disallows casts. Current signature: U opCast(U, this _)() if (isIntegral!U || isFloatingPoint!U || is(U == bool)) The compiler can figure out that all code paths end with an @pragma(noreturn), so it can add that pragma implicitly to the signature. However, the compiler can't change the return type from U to Bottom (otherwise static equality checks with U will fail). You can return 'auto' instead of U. Then the return type will be inferred either as U or Bottom.
Re: proposed @noreturn attribute
On 07/15/2017 11:30 PM, Walter Bright wrote: On 7/13/2017 5:18 PM, Andrei Alexandrescu wrote: On 7/13/17 2:37 PM, Timon Gehr wrote: On Thursday, 13 July 2017 at 17:25:18 UTC, Timon Gehr wrote: Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. ... (Actually, there are some complications like the .sizeof property. Anyway, it is clear what the semantics of Bottom are, no matter whether it is subtyping or implicit conversion.) I wonder if sizeof could be made size_t.max. -- Andrei I thought bottom.sizeof would be 0. My thinking comes from bottom being the subtype of all types in the universe. Therefore, it must include the state of all types. But let's wait for Timon. -- Andrei
Re: proposed @noreturn attribute
On 16.07.2017 05:30, Walter Bright wrote: On 7/13/2017 5:18 PM, Andrei Alexandrescu wrote: On 7/13/17 2:37 PM, Timon Gehr wrote: On Thursday, 13 July 2017 at 17:25:18 UTC, Timon Gehr wrote: Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. ... (Actually, there are some complications like the .sizeof property. Anyway, it is clear what the semantics of Bottom are, no matter whether it is subtyping or implicit conversion.) I wonder if sizeof could be made size_t.max. -- Andrei I thought bottom.sizeof would be 0. 0 is the obvious size for the unit type (the type with a single value, in D this is for example void[0]), as in: struct S{ T x; void[0] nothing; } static assert(S.sizeof == T.sizeof); on the other hand struct S{ T x; Bottom everything; } turns the entire struct into an empty type. It is therefore most natural to say that Bottom.sizeof == ∞. (It's the only choice for which S.sizeof == Bottom.sizeof.) Another way to think about it: If something of type A* converts to something of type B* without problems, then one would expect B.sizeof <= A.sizeof. This would imply that Bottom.sizeof >= size_t.max. (Because Bottom* converts to all other pointer types.) One small issue is that one needs to avoid overflow for the size of a struct that has multiple fields where one of them is of type Bottom.
Re: proposed @noreturn attribute
On 7/13/2017 5:18 PM, Andrei Alexandrescu wrote: On 7/13/17 2:37 PM, Timon Gehr wrote: On Thursday, 13 July 2017 at 17:25:18 UTC, Timon Gehr wrote: Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. ... (Actually, there are some complications like the .sizeof property. Anyway, it is clear what the semantics of Bottom are, no matter whether it is subtyping or implicit conversion.) I wonder if sizeof could be made size_t.max. -- Andrei I thought bottom.sizeof would be 0.
Re: proposed @noreturn attribute
On 07/14/2017 03:06 PM, Lurker wrote: On Friday, 14 July 2017 at 15:39:01 UTC, Guillaume Boucher wrote: Example 1: Polymorphism class Bird { void fly() { ... } }; class Penguin : Bird { override void fly() @pragma(noreturn) { assert(0); } }; class EvolvedPenguin : Penguin { override void fly() { ... } }; No matter how you look at it, this code should simply not be allowed: Bird bird = ...; bird.fly(); // is this return or noreturn? Penguin penguin = ...; penguin.fly(); // is this return or noreturn? In both cases, compiler cannot draw any conclusions about return/noreturn and thus I believe such code should not be allowed. Conventional thinking has it that derived methods should "require less and deliver more" such that substitution is possible. That's where contravariant parameters and covariant returns come from. Therefore, methods that do not return should be able to override those that return. (The opposite is unworkable btw.) Note that the absence of a "noreturn" annotation does not imply a guarantee that the method does return. Andrei
Re: proposed @noreturn attribute
On Friday, 14 July 2017 at 15:39:01 UTC, Guillaume Boucher wrote: Example 1: Polymorphism class Bird { void fly() { ... } }; class Penguin : Bird { override void fly() @pragma(noreturn) { assert(0); } }; class EvolvedPenguin : Penguin { override void fly() { ... } }; No matter how you look at it, this code should simply not be allowed: Bird bird = ...; bird.fly(); // is this return or noreturn? Penguin penguin = ...; penguin.fly(); // is this return or noreturn? In both cases, compiler cannot draw any conclusions about return/noreturn and thus I believe such code should not be allowed. And if this is disallowed, a Bottom type would fit again.
Re: proposed @noreturn attribute
On Monday, 10 July 2017 at 04:02:59 UTC, Nicholas Wilson wrote: 1)@noreturn 2)@disable(return) 3)none w.r.t optimisation assuming both 1 & 3 impact DMD equally [...] I don't think that's true. A Bottom type does not cover all use cases of @noreturn/@pragma(noreturn). Example 1: Polymorphism class Bird { void fly() { ... } }; class Penguin : Bird { override void fly() @pragma(noreturn) { assert(0); } }; class EvolvedPenguin : Penguin { override void fly() { ... } }; There's no way to encode that information in a return type. Example 2: Compile-time polymorphism Same as above, except during compile time. While it looks ok in theory (just return Bottom, and everything is alright), it seems very tricky to get right. Example from checkedint.d: auto r = hook.hookOpUnary!op(payload); return Checked!(typeof(r), Hook)(r); Let's say the hook refuses to perform hookOpUnary, so r is Bottom. Unfortunately, Checked!(Bottom, Hook)(r) doesn't compile (because "if (isIntegral!T || is(T == Checked!(U, H), U, H))" fails). While Bottom may be substituted into all expressions (which doesn't seem easy anyway), it for sure can't be inserted as any template argument. As seen before, Checked is not Bottom-proof. I would think that most templates are not Bottom-proof and making them Bottom-proof seems quite a bit of work. With @pragma(noreturn) that situation would be no problem. Example 3: Unreachable statements/Implicit noreturn inference As pointed out by Steven Schveighoffer, the current unreachability errors should probably be removed in generic code. If we do that, then generic functions can be @pragma(noreturn) if certain conditions are met. A compiler can easily figure that out, but writing it inside static ifs could be almost impossible. Assume we have a hook to Checked that disallows casts. Current signature: U opCast(U, this _)() if (isIntegral!U || isFloatingPoint!U || is(U == bool)) The compiler can figure out that all code paths end with an @pragma(noreturn), so it can add that pragma implicitly to the signature. However, the compiler can't change the return type from U to Bottom (otherwise static equality checks with U will fail).
Re: proposed @noreturn attribute
On 7/13/17 2:37 PM, Timon Gehr wrote: On Thursday, 13 July 2017 at 17:25:18 UTC, Timon Gehr wrote: Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. ... (Actually, there are some complications like the .sizeof property. Anyway, it is clear what the semantics of Bottom are, no matter whether it is subtyping or implicit conversion.) I wonder if sizeof could be made size_t.max. -- Andrei
Re: proposed @noreturn attribute
On Saturday, 8 July 2017 at 20:27:11 UTC, H. S. Teoh wrote: Also, a @noreturn attribute would allow overriding a non-void class method with a @noreturn one (e.g. the derived class is a sentinel object that forces an exception / termination upon calling that method), whereas you can't do that with a None return type because the signature would not match the base class's. T The reverse is also true, and more disastrous!
Re: proposed @noreturn attribute
On Thursday, 13 July 2017 at 17:25:18 UTC, Timon Gehr wrote: Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. ... (Actually, there are some complications like the .sizeof property. Anyway, it is clear what the semantics of Bottom are, no matter whether it is subtyping or implicit conversion.)
Re: proposed @noreturn attribute
On Wednesday, 12 July 2017 at 14:23:15 UTC, Andrei Alexandrescu wrote: On 07/12/2017 05:32 AM, Timon Gehr wrote: On 09.07.2017 23:45, Meta wrote: ... Another case that we should probably just statically disallow: ... > This obviously doesn't make any sense anyway ... > I don't see a reason for us to ever need to do that Sorry, but this thinking has no place in type system design. This is precisely how you create a convoluted nonsensical mess. Timon, I think you're very well positioned to author a DIP on this. Getting through acceptance on your static foreach DIP seems to not require a lot of extra work. ... I might do that, however there are a couple of open questions (see below). Every type is peculiar. That's essentially the point of having types. There is not really a reason to invent a peculiarity ordering and then add additional special casing for types deemed more peculiar. (I.e., creating different types of types based on an informal judgment of peculiarity.) I seem to recall Haskell calls those "kinds". ... Indeed, but the separation of types and kinds has no point. See: https://ghc.haskell.org/trac/ghc/wiki/DependentHaskell It's perfectly fine to have a type of types which is its own type, especially if you allow non-termination. In D, subtyping is messy anyway, as you cannot have a subtyping relationship between values with different memory layout. Hence in D, Bottom would not actually be a subtype of all other types. It's a point, and it would make the implementation easier, but it would be a departure from theory. Also it makes user code a tad more awkward. I'm saying the D notion of subtyping is a bit messy because memory layout matters and subtyping and implicit conversion are not the same thing. Anyway, my assertion that Bottom cannot be a subtype of all other types was actually incorrect: the compiler does not need to generate code for implicit conversion from Bottom to some other type, so it can be treated as a subtype. (Also, a language does not have to support subtyping to have an empty type.) typeof(assert(0))* and typeof(assert(0))[] will hence be subtypes of all other pointer and array types respectively. An issue is that we already have typeof(null). typeof(null) and typeof(assert(0))* are two ways to specify almost the same thing. One question is whether typeof(assert(0))* and typeof(null) should be the same, or if the former should not implicitly convert to class references. I have also argued in the past that there should be a separate typeof([]). This role would now be filled by typeof(assert(0))[]. However, changing the type of '[]' may break code. Consider: typeof(assert(0)) abort(const(char)[] message); ... int fun() { int x; ... return x != 0 ? 1024 / x : abort("Error: calculation went awry."); } I guess such expressions can be rewritten into separate statements: if (x != 0) return 1024 / x; abort("Error: calculation went awry."); and then the compiler figures there's no need for a return following the call to abort. ... This code compiles and runs: int x; ... return x != 0 ? 1024 : (delegate int(){ assert(0,"Error: calculation went awry."); })(); Perhaps a solid plan is to start with a DIP that does not introduce conversion and then experiment with the result for a while. What do you think? ... I think the DIP should introduce conversion from the start, as conversion is easy to support. It is simple to support in the front end and the code gen for it is literally to emit nothing.
Re: proposed @noreturn attribute
On 07/12/2017 05:32 AM, Timon Gehr wrote: On 09.07.2017 23:45, Meta wrote: ... Another case that we should probably just statically disallow: ... > This obviously doesn't make any sense anyway ... > I don't see a reason for us to ever need to do that Sorry, but this thinking has no place in type system design. This is precisely how you create a convoluted nonsensical mess. Timon, I think you're very well positioned to author a DIP on this. Getting through acceptance on your static foreach DIP seems to not require a lot of extra work. Every type is peculiar. That's essentially the point of having types. There is not really a reason to invent a peculiarity ordering and then add additional special casing for types deemed more peculiar. (I.e., creating different types of types based on an informal judgment of peculiarity.) I seem to recall Haskell calls those "kinds". In D, subtyping is messy anyway, as you cannot have a subtyping relationship between values with different memory layout. Hence in D, Bottom would not actually be a subtype of all other types. It's a point, and it would make the implementation easier, but it would be a departure from theory. Also it makes user code a tad more awkward. Consider: typeof(assert(0)) abort(const(char)[] message); ... int fun() { int x; ... return x != 0 ? 1024 / x : abort("Error: calculation went awry."); } I guess such expressions can be rewritten into separate statements: if (x != 0) return 1024 / x; abort("Error: calculation went awry."); and then the compiler figures there's no need for a return following the call to abort. Perhaps a solid plan is to start with a DIP that does not introduce conversion and then experiment with the result for a while. What do you think? Andrei
Re: proposed @noreturn attribute
On Wednesday, 12 July 2017 at 09:32:32 UTC, Timon Gehr wrote: On 09.07.2017 23:45, Meta wrote: ... Another case that we should probably just statically disallow: ... > This obviously doesn't make any sense anyway ... > I don't see a reason for us to ever need to do that Sorry, but this thinking has no place in type system design. This is precisely how you create a convoluted nonsensical mess. D is not ML or Haskell or Idris. Rust has trod this ground before us and they saw it prudent to not make ! a first-class type. I think this is both a concession to usability and an acceptable compromise for a systems programming language.
Re: proposed @noreturn attribute
On 09.07.2017 23:45, Meta wrote: ... Another case that we should probably just statically disallow: ... > This obviously doesn't make any sense anyway ... > I don't see a reason for us to ever need to do that Sorry, but this thinking has no place in type system design. This is precisely how you create a convoluted nonsensical mess.
Re: proposed @noreturn attribute
On 11.07.2017 19:27, Meta wrote: On Tuesday, 11 July 2017 at 08:29:12 UTC, Timon Gehr wrote: On 10.07.2017 18:23, Meta wrote: ... problems with stuff like typeof(null)* etc. because for the most part it's just a regular type, unlike Bottom. Bottom is just a regular type. It's a regular type with unusual behaviour due to it being uninhabited. All types are unusual. That does not mean they are not all types.
Re: proposed @noreturn attribute
On 12.07.2017 03:50, Andrei Alexandrescu wrote: On 7/11/17 4:29 AM, Timon Gehr wrote: On 10.07.2017 18:23, Meta wrote: ... problems with stuff like typeof(null)* etc. because for the most part it's just a regular type, unlike Bottom. Bottom is just a regular type. Wouldn't the fact that it's a subtype of all other types make it a bit more peculiar? -- Andrei Every type is peculiar. That's essentially the point of having types. There is not really a reason to invent a peculiarity ordering and then add additional special casing for types deemed more peculiar. (I.e., creating different types of types based on an informal judgment of peculiarity.) In D, subtyping is messy anyway, as you cannot have a subtyping relationship between values with different memory layout. Hence in D, Bottom would not actually be a subtype of all other types. In a very expressive type system, there are many more, functionally different types that are uninhabited, not just Bottom.
Re: proposed @noreturn attribute
On 7/11/17 4:29 AM, Timon Gehr wrote: On 10.07.2017 18:23, Meta wrote: ... problems with stuff like typeof(null)* etc. because for the most part it's just a regular type, unlike Bottom. Bottom is just a regular type. Wouldn't the fact that it's a subtype of all other types make it a bit more peculiar? -- Andrei
Re: proposed @noreturn attribute
On Saturday, 8 July 2017 at 12:18:38 UTC, Andrei Alexandrescu wrote: On 7/8/17 7:07 AM, bachmeier wrote: On Saturday, 8 July 2017 at 10:15:39 UTC, Walter Bright wrote: Having an @noreturn attribute will take care of that: @noreturn void ThisFunctionExits(); Why should this be an attribute rather than a pragma? So it's part of the summary of the function. -- Andrei If it feels like a pragma, should be part of the function and reflectable, then how about: void assertFalse(bool cond) @pragma(noreturn) or void assertFalse(bool cond) @pragma("noreturn") The compiler could probably give an error if the "" (inside @pragma) wasn't a known string. Also @pragma would be useful as standard way of saying "special compiler attribute". No need to consume global attribute namespace. I'm expecting to see @myproject_safe and @myproject_noreturn type of attributes someday in some project :|
Re: proposed @noreturn attribute
On Monday, 10 July 2017 at 20:00:10 UTC, Steven Schveighoffer wrote: This means that you get errors for some instantiations. Which ironically means you'd need to do something like this: void foo(alias f)() { f(); static if(!isNoreturn!f) { auto a = 5; ...// etc. } } Today, it's not a big issue. We can't alias `assert` function directly, so it's obvious where it's an assert or not (because you have to spell it out!). We have similar problems today with generic code causing unreachability errors. See for instance https://issues.dlang.org/show_bug.cgi?id=14835 -Steve I think that for our own sanity the dead-code check would have to be disabled in this case. I agree that it'd be awful putting `static if (!isNoReturn!f)` everywhere. Actually, why not just disable it entirely in templated functions?
Re: proposed @noreturn attribute
On Tuesday, 11 July 2017 at 08:29:12 UTC, Timon Gehr wrote: On 10.07.2017 18:23, Meta wrote: ... problems with stuff like typeof(null)* etc. because for the most part it's just a regular type, unlike Bottom. Bottom is just a regular type. It's a regular type with unusual behaviour due to it being uninhabited.
Re: proposed @noreturn attribute
On 10.07.2017 04:44, Walter Bright wrote: Let's call the bottom type 'B' for the moment, for convenience. If we think of it like a floating point NaN, It's not. It's an empty type. then any type construction of B yields a B: const(B) -> B I don't see why to add this special case. B* -> B B[] -> B X[B] -> B B[X] -> B ... This would be wrong. All of the types on the left have valid values, they are not isomorphic to B. Since B cannot have a value, any expression that forms a B can be replaced with an assert(0). B foo(); // declaration foo() -> foo(); assert(0); Yes. cast(B)exp -> exp; assert(0); B b; -> assert(0); Those wouldn't compile. (Nothing can be cast to bottom, there is no default initializer that the variable declaration can use.) Given a tuple of types: alias T = tuple(B,X); is T equivalent to which of: B (1) tuple(X)(2) tuple(Y,X) (3) tuple(B,X) (4) ? I'm leaning toward (4) as making the most sense. ... It's the only one that makes any sense. struct S { T t; } should then yield an error, while: struct S { T[1..1] t; // t is of type X } would not. I guess you meant T[1..2].
Re: proposed @noreturn attribute
On 10.07.2017 18:23, Meta wrote: ... problems with stuff like typeof(null)* etc. because for the most part it's just a regular type, unlike Bottom. Bottom is just a regular type.
Re: proposed @noreturn attribute
On 2017-07-11 09:37, Iain Buclaw via Digitalmars-d wrote: Right, you can't put noreturn on enforce itself, but you can on the internal bailOut function called by enforce. Ah, but I though it would just contain a "throw" for the case the the condition is false. I see now that it doesn't. -- /Jacob Carlborg
Re: proposed @noreturn attribute
On 08.07.2017 12:15, Walter Bright wrote: C compilers (and by extension C++ compilers) usually have an extension which allows a function to be marked as one that never returns. The point of this is it enables improved data flow analysis and better code being generated. Noreturn functions crop up in things like assert's and enforce's. DMD internally hardcodes a few functions it knows about that are noreturn, and the DMD optimizer and codegen take advantage of it. But when people write their own assert's and enforce's, this falls apart. While the programs will still work, they won't be as efficient as they could be. Having an @noreturn attribute will take care of that: @noreturn void ThisFunctionExits(); Yes, it's another builtin attribute and attributes are arguably a failure in language design. I don't like the inflation of attributes, too, but encoding it into the return type seems too clever, especially when having to explain it again and again to people without functional language background (like me). A few questions inspired from discussion in https://github.com/dlang/druntime/pull/1839: - Does @noreturn need to be inferred for templates? void msgAssert(bool cond)(string msg) { debug writeln(msg); assert(cond); } - The template function above is (strongly) pure, how does @noreturn interact with that? Will @noreturn ensure it is not elided? - If it does, how does this propagate to a function calling it, e.g. void c_assert(bool cond, string msg) pure { if (!cond) msgAssert!false(msg); } A call to c_assert can be elided according to the pure rules. Any chance that this can be avoided with the help of @noreturn?
Re: proposed @noreturn attribute
On 11 July 2017 at 08:46, Jacob Carlborg via Digitalmars-dwrote: > On 2017-07-10 22:00, Walter Bright wrote: > >> Yes. Not having it makes enforce(), for example, generate poor code. > > > Not sure I understand. "enforce" will return if the condition is true. > Right, you can't put noreturn on enforce itself, but you can on the internal bailOut function called by enforce.
Re: proposed @noreturn attribute
On 2017-07-10 22:00, Walter Bright wrote: Yes. Not having it makes enforce(), for example, generate poor code. Not sure I understand. "enforce" will return if the condition is true. -- /Jacob Carlborg
Re: proposed @noreturn attribute
Am Sat, 8 Jul 2017 03:15:39 -0700 schrieb Walter Bright: > […] > > Having an @noreturn attribute will take care of that: > > @noreturn void ThisFunctionExits(); > > Yes, it's another builtin attribute and attributes are arguably a failure in > language design. The 'none' return type sounds interesting, because a @noreturn function is also a void function, it is practical to implement this as a void sub-type or compiler recognized druntime defined "type intrinsic". On the other hand, the attribute solution has worked well for the existing compilers in practice and such a rarely used tag doesn't add significantly to the meticulous D programmers list: "pure @safe nothrow @nogc". -- Marco
Re: proposed @noreturn attribute
On 7/10/2017 12:02 PM, Jacob Carlborg wrote: Are those few cases worth optimizing for? Yes. Not having it makes enforce(), for example, generate poor code.
Re: proposed @noreturn attribute
On 7/10/17 3:05 PM, Meta wrote: On Monday, 10 July 2017 at 18:50:54 UTC, Steven Schveighoffer wrote: On 7/10/17 2:38 PM, Walter Bright wrote: On 7/10/2017 4:00 AM, Steven Schveighoffer wrote: But I have to ask, what is the benefit of statically determining that a function is noreturn? It is useful anywhere dataflow analysis is useful. FunctionThatDoesnotReturn(); a = b; // error: unreachable code That doesn't require static introspection. The compiler can see that, the user doesn't have to worry about it. Note, one thing that hasn't been mentioned is how we are now going to be able to make regular functions noreturn. This means templates that accept aliases will now have to deal with the possibility that those aliases are noreturn. So if the compiler, for instance, marks the above as an error, what happens here? foo(alias f)() { f(); auto a = b; } if f is a noreturn function, is this instantiation an error? Currently not. This is either a bug or the compiler's flow analysis is not robust enough to detect this case. I think the implication from Walter is that f would be treated just like a direct call to assert(0) (i.e. it doesn't return). So where code like this produces an "unreachable statement" error: void foo() { assert(0); auto a = b; } with dmd -w, code like the above will potentially produce an unreachable code error if f is a noreturn (the compiler can now do dataflow analysis and determine it's unreachable). This means that you get errors for some instantiations. Which ironically means you'd need to do something like this: void foo(alias f)() { f(); static if(!isNoreturn!f) { auto a = 5; ...// etc. } } Today, it's not a big issue. We can't alias `assert` function directly, so it's obvious where it's an assert or not (because you have to spell it out!). We have similar problems today with generic code causing unreachability errors. See for instance https://issues.dlang.org/show_bug.cgi?id=14835 -Steve
Re: proposed @noreturn attribute
On 7/10/2017 12:05 PM, Meta wrote: Currently not. This is either a bug or the compiler's flow analysis is not robust enough to detect this case. Flow analysis relies on the function's signature, not its implementation, and currently the signature contains no information about noreturn. Addressing this is the whole point of this thread.
Re: proposed @noreturn attribute
Jacob Carlborg wrote: I'm going to ask the stupid question: I understand that this is for the compiler to generate better code. But, since the attribute (or whatever it is) indicates that a function won't return, it can only be used in very few cases. Are those few cases worth optimizing for? the case that makes @noreturn worth having is even not optimizing, but don't adding visual noise at the call site. case Smth: error("boo"); case Other: ... oops. i know that `error()` will never return, but compiler doesn't, and insisting on adding `break;` there. sure, i can either put break, or always put `assert(0);` after noreturn functions, but hey, aren't we invented computers exactly to lay off such borning things onto them!? ;-)
Re: proposed @noreturn attribute
On Monday, 10 July 2017 at 18:09:54 UTC, H. S. Teoh wrote: On Sun, Jul 09, 2017 at 02:49:35PM -0400, Nick Sabalausky (Abscissa) via Digitalmars-d wrote: On 07/09/2017 06:51 AM, Daniel N wrote: > On Sunday, 9 July 2017 at 10:31:47 UTC, Mr.D wrote: > > On Saturday, 8 July 2017 at 10:15:39 UTC, Walter Bright > > wrote: > > > > > Has anyone a better idea? > > > > What about > > > > scope(exit) assert(0); > > > > ? > > void func() > out { assert(0); } > body > { > } Too indirect and verbose. An attribute or special "return type" would just cut straight to the case. If DIP 1009 is accepted, this would not be verbose at all: void func() out(false) // it even tells you it won't return { ... } Plus, this has the advantage that you can specify a valid return type for when you need to override a base class method, e.g.: class JitCompiler { Code compile(string code); } class InvalidCompiler : JitCompiler { override Code compile(string code) out(false) {...} } A Bottom type that implicitly converts to anything would also fit the bill, granted, but does require changing the language. The main thing I have against adding a Bottom type is that it adds yet another built-in type to the language, which means (1) a combinatorial explosion of existing language constructs combined with the new type, with currently-unknown consequences (and possibly corner cases we haven't thought of that will come back to bite us), (2) yet another special type newcomers have to learn with special semantics (I can already anticipate complaints to D.learn about what's the difference between null and bottom); (3) having to implement lots of compiler changes to handle how this new type interacts with operators and other types in all possible cases; (4) all of this just for something that (a) is only rarely used, and (b) could have been easily implemented by adding @noreturn or using existing contract syntax without adding a whole new basic type to the language. Honestly, I'd vote for @noreturn as the simplest, most straightforward solution, and the only reason I'm arguing for out{assert(0);} (or out(false) if DIP 1009 is accepted) is because people are all up in arms about adding Gosh Yet Another Special UDA In Addition To The Numerous Special UDAs We Already Have Like @safe and @nogc. +1
Re: proposed @noreturn attribute
On Monday, 10 July 2017 at 18:50:54 UTC, Steven Schveighoffer wrote: On 7/10/17 2:38 PM, Walter Bright wrote: On 7/10/2017 4:00 AM, Steven Schveighoffer wrote: But I have to ask, what is the benefit of statically determining that a function is noreturn? It is useful anywhere dataflow analysis is useful. FunctionThatDoesnotReturn(); a = b; // error: unreachable code That doesn't require static introspection. The compiler can see that, the user doesn't have to worry about it. Note, one thing that hasn't been mentioned is how we are now going to be able to make regular functions noreturn. This means templates that accept aliases will now have to deal with the possibility that those aliases are noreturn. So if the compiler, for instance, marks the above as an error, what happens here? foo(alias f)() { f(); auto a = b; } if f is a noreturn function, is this instantiation an error? Currently not. This is either a bug or the compiler's flow analysis is not robust enough to detect this case. int b; auto foo(alias f)() { f(); auto a = b; //no unreachable code error } void main() { foo!(() => assert(0))(); }
Re: proposed @noreturn attribute
On 2017-07-08 12:15, Walter Bright wrote: C compilers (and by extension C++ compilers) usually have an extension which allows a function to be marked as one that never returns. The point of this is it enables improved data flow analysis and better code being generated. Noreturn functions crop up in things like assert's and enforce's. DMD internally hardcodes a few functions it knows about that are noreturn, and the DMD optimizer and codegen take advantage of it. But when people write their own assert's and enforce's, this falls apart. While the programs will still work, they won't be as efficient as they could be. I'm going to ask the stupid question: I understand that this is for the compiler to generate better code. But, since the attribute (or whatever it is) indicates that a function won't return, it can only be used in very few cases. Are those few cases worth optimizing for? -- /Jacob Carlborg
Re: proposed @noreturn attribute
On 7/10/17 2:38 PM, Walter Bright wrote: On 7/10/2017 4:00 AM, Steven Schveighoffer wrote: But I have to ask, what is the benefit of statically determining that a function is noreturn? It is useful anywhere dataflow analysis is useful. FunctionThatDoesnotReturn(); a = b; // error: unreachable code That doesn't require static introspection. The compiler can see that, the user doesn't have to worry about it. Note, one thing that hasn't been mentioned is how we are now going to be able to make regular functions noreturn. This means templates that accept aliases will now have to deal with the possibility that those aliases are noreturn. So if the compiler, for instance, marks the above as an error, what happens here? foo(alias f)() { f(); auto a = b; } if f is a noreturn function, is this instantiation an error? That's going to get messy. It's not a problem today, because you can't alias `assert`, and the compiler doesn't care about other functions that don't return (even if they are completely available). I learned the hard way with inout not to proactively make obvious errors errors. For instance, you can't return inout if you don't have any inout parameters. It makes complete logical sense when you think about it, just use const. This leads to the (inout int = 0) crap we see everywhere in phobos. -Steve
Re: proposed @noreturn attribute
On 7/10/2017 4:00 AM, Steven Schveighoffer wrote: But I have to ask, what is the benefit of statically determining that a function is noreturn? It is useful anywhere dataflow analysis is useful. FunctionThatDoesnotReturn(); a = b; // error: unreachable code
Re: proposed @noreturn attribute
On Sun, Jul 09, 2017 at 02:49:35PM -0400, Nick Sabalausky (Abscissa) via Digitalmars-d wrote: > On 07/09/2017 06:51 AM, Daniel N wrote: > > On Sunday, 9 July 2017 at 10:31:47 UTC, Mr.D wrote: > > > On Saturday, 8 July 2017 at 10:15:39 UTC, Walter Bright wrote: > > > > > > > Has anyone a better idea? > > > > > > What about > > > > > > scope(exit) assert(0); > > > > > > ? > > > > void func() > > out { assert(0); } > > body > > { > > } > > Too indirect and verbose. An attribute or special "return type" would > just cut straight to the case. If DIP 1009 is accepted, this would not be verbose at all: void func() out(false) // it even tells you it won't return { ... } Plus, this has the advantage that you can specify a valid return type for when you need to override a base class method, e.g.: class JitCompiler { Code compile(string code); } class InvalidCompiler : JitCompiler { override Code compile(string code) out(false) {...} } A Bottom type that implicitly converts to anything would also fit the bill, granted, but does require changing the language. The main thing I have against adding a Bottom type is that it adds yet another built-in type to the language, which means (1) a combinatorial explosion of existing language constructs combined with the new type, with currently-unknown consequences (and possibly corner cases we haven't thought of that will come back to bite us), (2) yet another special type newcomers have to learn with special semantics (I can already anticipate complaints to D.learn about what's the difference between null and bottom); (3) having to implement lots of compiler changes to handle how this new type interacts with operators and other types in all possible cases; (4) all of this just for something that (a) is only rarely used, and (b) could have been easily implemented by adding @noreturn or using existing contract syntax without adding a whole new basic type to the language. Honestly, I'd vote for @noreturn as the simplest, most straightforward solution, and the only reason I'm arguing for out{assert(0);} (or out(false) if DIP 1009 is accepted) is because people are all up in arms about adding Gosh Yet Another Special UDA In Addition To The Numerous Special UDAs We Already Have Like @safe and @nogc. T -- The diminished 7th chord is the most flexible and fear-instilling chord. Use it often, use it unsparingly, to subdue your listeners into submission!