On Monday, 10 July 2017 at 03:25:26 UTC, Nick Sabalausky
(Abscissa) wrote:
On 07/09/2017 05:14 PM, H. S. Teoh via Digitalmars-d wrote:
On Sun, Jul 09, 2017 at 02:01:08PM -0400, Andrei Alexandrescu
via Digitalmars-d wrote:
On 07/09/2017 12:19 PM, Steven Schveighoffer wrote:
It's no more of a hack than leaving assert(0) in release
code.
I wouldn't argue that. I do argue it's a hack compared to the
principled solution of a bottom type. -- Andrei
I like out{ assert(0); } for pretty much the same reasons as
Steven
lists. The biggest pro is that **the language already supports
it*.
Contract syntax already is meant to signal intent, and
assert(0) signals
"never gets here". You can't find a better solution than this.
All the
other alternatives require adding even more baggage to an
already
heavy language, or compiler voodoo to recognize a particular
pattern of
defining a type. I'd say out{assert(0);} is the principled
solution --
expressing something the current language can already express,
and it's
the other alternatives that are "exotic".
Prioritizing "path of least resistense" over "this is cleaner
and more principled" is the hallmark of C++-style langauge
design. Please, please, please, let's stay away from that path.
While I agree with your sentiment in principle (heh), we need to
keep in mind it purpose.
So far I count four requirements of a solution:
documentation
optimisation
ability to statically reflect upon
ability to implement
Of the approached listed only out{assert(0);} fails the static
reflection check.
Which leaves
1)@noreturn
2)@disable(return)
3)none
1 & 2 are almost functionally identical in their implementation
with 2 requiring some semantic hacks to the compiler and
precludes the AliasSeq approach below, so I consider 1 to be
superior to 2.
this leaves 1 & 3.
w.r.t documentation for 1 this is a solved problem, it becomes
part of the type signature and will be picked up in the
documentation building tools. 3 it becomes part of the return
type and can also be solved by documenting the type.
w.r.t optimisation assuming both 1 & 3 impact DMD equally then
there is no difference except that:
Implementation: 3 would require GDC and LDC to make changes _when
they already have a solution_. It would also be _considerably
more work_ than 1, and would be _backwards incompatible_ with
older compilers. In fact 1 could be implemented _Immediately_ for
GDC and LDC by having
enum __noreturn;
version (DigitalMars) alias noreturn = __noreturn;
else version(GNU) {
import gcc.attributes : attribute;
alias noreturn = AliasSeq!(__noreturn,attribute("noreturn"));
}
else version (LDC)
{
import ldc.attributes : llvmAttr;
alias noreturn = AliasSeq!(__noreturn,llvmAttr("noreturn"));
}
and reflect upon the presence of __noreturn;
I am strongly against the need to complicate the compiler when an
equal (IMHO better) solution _already exists_, for extremely
marginal gain: anyone seriously concerned about the small
optimisation benefit will already be using GDC or LDC, the
applicability of noreturn is minuscule, AFAICT C's _exit and an
unconditional throw (Exception or Error) are the only functions
for which it applies.