digitalmars.D.learn - A few questions
- Namespace (40/40) Jul 27 2012 1.
- monarch_dodra (8/16) Jul 27 2012 Some would argue only the *first* should be valid:
- Jacob Carlborg (19/40) Jul 27 2012 The reason "const Foo some_function" is allowed is because in D this
- Jacob Carlborg (5/18) Jul 27 2012 Forgot to say, the reason for why the ref(Foo) syntax isn't used is
- Namespace (3/10) Jul 27 2012 Good point. I had completely forgotten, that that is possible.
- bearophile (5/8) Jul 27 2012 Similar things were discussed a lot. And some people think that
- Namespace (9/17) Jul 27 2012 Then: What is the problem to introduce such shorthand?
- bearophile (6/7) Jul 27 2012 I don't know.
- Simen Kjaeraas (9/16) Jul 27 2012 I believe at least part of the explanation is that Walter wants NotNull ...
- Namespace (36/36) Jul 27 2012 bearophile:
- Namespace (1/1) Jul 27 2012 Short improvement: http://dpaste.dzfl.pl/f3263def
- bearophile (14/18) Jul 27 2012 Yes, I remember part of the discussions. And I agree that
- Namespace (9/9) Jul 27 2012 What's wrong with the solution that
- Simen Kjaeraas (10/19) Jul 27 2012 Nope.
- Timon Gehr (3/7) Jul 29 2012 Non-null types in Spec# are unsound.
- bearophile (7/8) Jul 29 2012 Really? I didn't know it. Surely its non-null design looks quite
- Timon Gehr (5/10) Jul 29 2012 Google for "freedom before commitment". The example is in the paper.
- Jonathan M Davis (22/39) Jul 27 2012 Sadly, the reason is consistency. const is an attribute just like pure o...
- Namespace (20/26) Jul 27 2012 That is a huge mistake. My OS prints me only a funny "Access
- Jonathan M Davis (16/46) Jul 27 2012 Because a debugger will show you exactly where the problem is. So, why a...
- Namespace (9/9) Jul 27 2012 I also get null references (and every time i hate D a bit more),
- Era Scarecrow (37/46) Jul 27 2012 I've noticed when debugging the 'segfault' is rather vague, but
- Adam D. Ruppe (8/8) Jul 27 2012 On Windows, an access violation (from a null pointer or other
- Era Scarecrow (3/7) Jul 27 2012 Linux also dumps the state into a file. So I'd have to wonder
- Adam D. Ruppe (7/8) Jul 27 2012 Only if core dumps are enabled... but I think someone did
- Artur Skawina (82/87) Jul 27 2012 It's not a regular D exception, but it is a signal that /can/
- Namespace (7/7) Jul 27 2012 And that is the explicit way with pre- and postconditions of
- Namespace (22/22) Jul 27 2012 Me again.
- Jonathan M Davis (10/13) Jul 27 2012 Doing stuff like that makes your code completely unportable. It's _bad_
- Namespace (9/9) Jul 27 2012 Therefore i hope that it will be official added into D.
- Adam D. Ruppe (9/9) Jul 27 2012 I started a not null struct for phobos but then had to
- Jonathan M Davis (21/31) Jul 27 2012 I don't even know what the last time I dereferenced a null pointer or nu...
- bearophile (24/30) Jul 27 2012 In the case of not-nullability, this isn't true. Integrating
- Jonathan M Davis (27/62) Jul 27 2012 ??? What does it matter if the type system knows whether a pointer is nu...
- bearophile (15/25) Jul 27 2012 In the else branch the state of the type of x is not-null, so as
- Marco Leise (6/27) Jul 28 2012 I found this an interesting read. The implementation likely doesn't inte...
- Namespace (2/19) Jul 28 2012 I can give them the "clone_*.d" files, which contains valid D
- Namespace (4/4) Jul 28 2012 One more question: Where can I find an official statement by
- Simen Kjaeraas (9/15) Jul 27 2012 This is a NotNull I just implemented. It is designed to create a strict
- Namespace (18/27) Jul 28 2012 Foo f = new Foo();
- Simen Kjaeraas (14/29) Jul 28 2012 The conversion from a pointer to a struct containing a pointer should be
- Namespace (3/14) Jul 28 2012 Some kind of smart pointer is easy to write, or not?
- Simen Kjaeraas (19/23) Jul 27 2012 Like monarch_dodra said, this is also a style favored by some:
- Jonathan M Davis (15/46) Jul 27 2012 Personally, I _always_ put the attributes on the right-hand side save fo...
1. Why are these two method header identitcal? const Foo some_function() { and Foo some_function() const { ? IMO that isn't consistent. IMO only the last is valid. With this example, it is somewhat understandable. // C++ class Bar { const Foo getFooObj() const { ... } const Foo& getFooObjRef const { ... } }; // D class Bar { const(Foo) getFooObj() const { ... } ref Foo getObjRef() { ... } } const(Foo) but ref Foo. This is inconsistency, if you ask me. So why is between C++ and D such a huge difference? Why isn't it simply const Foo instead of const(Foo)? 2. What's about a shorthand for debug assertions? E.g. to avoid not-null references (yes, if you're a windows user, you hate them): Example: [code] void some_function(Foo !f) { [/code] will automatically converted by the compiler into: [code] void some_function(Foo f, string filename = __FILE__, uint line = __LINE__) in { assert(f !is null, format("Null Object file %s on line %d.", filename, line)); } body { [/code] That would be avoid many many efforts by writing safe code. And it avoids Java code stil with explizit pre- and postconditions which blows up code.
Jul 27 2012
On Friday, 27 July 2012 at 10:29:15 UTC, Namespace wrote:1. Why are these two method header identitcal? const Foo some_function() { and Foo some_function() const { ? IMO that isn't consistent. IMO only the last is valid. With this example, it is somewhat understandable.Some would argue only the *first* should be valid: ---- safe const property nothrow Foo some_function(); ---- Basically, yeah, you have the option of putting qualifiers before or after.
Jul 27 2012
On 2012-07-27 12:29, Namespace wrote:1. Why are these two method header identitcal? const Foo some_function() { and Foo some_function() const { ?The reason "const Foo some_function" is allowed is because in D this syntax is possible: class Foo { const: Foo some_function () {} }IMO that isn't consistent. IMO only the last is valid. With this example, it is somewhat understandable. // C++ class Bar { const Foo getFooObj() const { ... } const Foo& getFooObjRef const { ... } }; // D class Bar { const(Foo) getFooObj() const { ... } ref Foo getObjRef() { ... } } const(Foo) but ref Foo. This is inconsistency, if you ask me. So why is between C++ and D such a huge difference? Why isn't it simply const Foo instead of const(Foo)?I think the reason is the same as above. If the return value is const you need to use parentheses. I think that the syntax would conflict with the const-method syntax otherwise. The reason for why const is allowed after the paramter list is because it can be a bit confusing to have two const next to each other. class Foo { const const (Foo) foo () {} } -- /Jacob Carlborg
Jul 27 2012
On 2012-07-27 13:14, Jacob Carlborg wrote:On 2012-07-27 12:29, Namespace wrote:Forgot to say, the reason for why the ref(Foo) syntax isn't used is because there can be no conflict since methods cannot be declared as const. -- /Jacob Carlborgconst(Foo) but ref Foo. This is inconsistency, if you ask me. So why is between C++ and D such a huge difference? Why isn't it simply const Foo instead of const(Foo)?I think the reason is the same as above. If the return value is const you need to use parentheses. I think that the syntax would conflict with the const-method syntax otherwise. The reason for why const is allowed after the paramter list is because it can be a bit confusing to have two const next to each other. class Foo { const const (Foo) foo () {} }
Jul 27 2012
The reason "const Foo some_function" is allowed is because in D this syntax is possible: class Foo { const: Foo some_function () {} }Good point. I had completely forgotten, that that is possible. But it seems that no one would have interest in my second proposal. :)
Jul 27 2012
Namespace:Good point. I had completely forgotten, that that is possible. But it seems that no one would have interest in my second proposal. :)Similar things were discussed a lot. And some people think that similar nonnull annotations are a good idea. Bye, bearophile
Jul 27 2012
On Friday, 27 July 2012 at 11:50:46 UTC, bearophile wrote:Namespace:Then: What is the problem to introduce such shorthand? To solve the problem with a struct is IMO a really _bad_ idea. Because then you have to pack the object into the struct (or you have to create the object with a function that returns this struct, equally as "scoped" does it currently) and _then_ you can pass it to the function/method. Still the same effort as if you solve it with preconditions. Completely unnecessary work, and such shorthand can avoid this.Good point. I had completely forgotten, that that is possible. But it seems that no one would have interest in my second proposal. :)Similar things were discussed a lot. And some people think that similar nonnull annotations are a good idea. Bye, bearophile
Jul 27 2012
Namespace:Then: What is the problem to introduce such shorthand?I don't know. I have a partial enhancement on the topic: http://d.puremagic.com/issues/show_bug.cgi?id=4571 Bye, bearophile
Jul 27 2012
On Fri, 27 Jul 2012 14:44:35 +0200, bearophile <bearophileHUGS lycos.com> wrote:Namespace:I believe at least part of the explanation is that Walter wants NotNull to implemented in a library. That's part of the reason for introducing disable this(). Now, one could certainly argue that int? be translated by the compiler into NotNull!int, and the implementation lie in druntime. -- SimenThen: What is the problem to introduce such shorthand?I don't know. I have a partial enhancement on the topic: http://d.puremagic.com/issues/show_bug.cgi?id=4571 Bye, bearophile
Jul 27 2012
bearophile: Yes i know, but i see there no answers. Simen Kjaeraas: That's exactly what i mean. Foo? or Foo! would be converted into NotNull!Foo. I wrote a quick and dirty solution: http://dpaste.dzfl.pl/400079cb Which converts this Code: [code] import std.stdio; class Foo { public: void echo() const { writeln("My Name is Foo."); } } void foo(Foo! f) { f.echo(); } void bar(Foo! f) { f.echo(); } void main() { Foo f = new Foo(); Foo f2; foo(f); bar(f2); foo(new Foo()); bar(null); } [/code] into: http://dpaste.dzfl.pl/d9375eeb It is not perfect, but a first step. It would be desirable if the dmd compiler could do something on its own. What are the chances that something like this happens?
Jul 27 2012
Short improvement: http://dpaste.dzfl.pl/f3263def
Jul 27 2012
Simen Kjaeraas:I believe at least part of the explanation is that Walter wants NotNull to implemented in a library. That's part of the reason for introducing disable this().Yes, I remember part of the discussions. And I agree that generally it's better to put meta-features in a language that allow library code to implement the desired features. That's why recently in the main D newsgroup I have said that built-in vector ops may be better replaced by library code (what's missing is some built-in trick to avoid the creation of intermediate arrays in complex expression). But implementing good non-null types in library code is hard (rather harder than implementing vector ops in library code on library defined vectors). I think disable isn't enough to cover Bye, bearophile
Jul 27 2012
What's wrong with the solution that void some_function(Foo? f) { is converted to void some_function(Foo f, string filename = __FILE__, uint line = __LINE__) in { assert(f !is null, std.string.format("Null Object File %s on Line %d.", filename, line)); } body { ? It isn't a huge effort for the compiler, or?
Jul 27 2012
On Fri, 27 Jul 2012 16:39:49 +0200, Namespace <rswhite4 googlemail.com> wrote:What's wrong with the solution that void some_function(Foo? f) { is converted to void some_function(Foo f, string filename = __FILE__, uint line = __LINE__) in { assert(f !is null, std.string.format("Null Object File %s on Line %d.", filename, line)); } body { ? It isn't a huge effort for the compiler, or?Nope. But, that's just a simple assertion. If we'd had real non-nullable types, we could remove the check completely, because you'd know it held a valid object. Now, a library solution has certain limitations a built-in solution would not - for instance, new X would return non-nullable. -- Simen
Jul 27 2012
On 07/27/2012 04:35 PM, bearophile wrote:But implementing good non-null types in library code is hardIt is closer to impossible than to hard.(rather harder than implementing vector ops in library code on library defined non-null types are meant to be.
Jul 29 2012
Timon Gehr:Really? I didn't know it. Surely its non-null design looks quite refined and thought-out. But maybe as say it's not enough still. Do you have a link where it shows it's unsound? Thank you, bye, bearophile
Jul 29 2012
On 07/29/2012 06:24 PM, bearophile wrote:Timon Gehr:Google for "freedom before commitment". The example is in the paper. Apparently the unsoundness was recently fixed though -- the faulty compiler.Really? I didn't know it. Surely its non-null design looks quite refined and thought-out. But maybe as say it's not enough still. Do you have a link where it shows it's unsound?
Jul 29 2012
On Friday, July 27, 2012 12:29:13 Namespace wrote:1. Why are these two method header identitcal? const Foo some_function() { and Foo some_function() const { ?const(Foo) but ref Foo. This is inconsistency, if you ask me. So why is between C++ and D such a huge difference? Why isn't it simply const Foo instead of const(Foo)?Sadly, the reason is consistency. const is an attribute just like pure or nothrow, and you can do both pure Foo func() {} and Foo func() pure {} as well as pure { Foo func() {} } and pure : Foo func() {} If const Foo func() {} made Foo const rather than func, it would be inconsistent with the other attributes, and if const on func were only legal on the right (as in C++), then it would be inconsistent with the others. Many of us think that const Foo func() {} should just become illegal inconsistency or not because of all of this confusion, but Walter doesn't buy into that.2. What's about a shorthand for debug assertions? E.g. to avoid not-null references (yes, if you're a windows user, you hate them):Walter's stand on this is that the OS gives you null-dereferencing detection - i.e. segfaults and access violations. He's not going to add extra syntax for it. - Jonathan M Davis
Jul 27 2012
Walter's stand on this is that the OS gives you null-dereferencing detection - i.e. segfaults and access violations. He's not going to add extra syntax for it. - Jonathan M DavisThat is a huge mistake. My OS prints me only a funny "Access violation". And so i can search for my little null reference by myself. I _must_ debug for a ridiculous null reference. That cost time. I have not even a filename or a line number. Only the message that something went wrong. And all other i have to find by myself. So much time for such little mistakes. Why would Walter have a language which doesn't support good error handling? D hasn't support for unused variables, unused imports and even not for null references. Why should everyone use D instead of any other language? If i have a big project and i use many objects and one of them change to null, what now? Should the user really step through thousand lines of code because D prints only "Access Violation" without any further information? Or should i use the same principle as Java, and write every time again pre- and postconditions? I don't see any reasons why anybody should realize a big project with D and not with a other language, if the error handling and not null support remains as it is. Sorry. To reject even a such handy shorthand is incomprehensible to me.
Jul 27 2012
On Friday, July 27, 2012 20:07:56 Namespace wrote:Because a debugger will show you exactly where the problem is. So, why add checking that the OS already does for you? That's his logic. There are plenty of cases where that really isn't enough (e.g. you get a segfault on a server application without core dumps turned on when it's been running for 2 weeks), but it is for all the types of programs that Walter works on, so that's the way he thinks.Walter's stand on this is that the OS gives you null-dereferencing detection - i.e. segfaults and access violations. He's not going to add extra syntax for it. - Jonathan M DavisThat is a huge mistake. My OS prints me only a funny "Access violation". And so i can search for my little null reference by myself. I _must_ debug for a ridiculous null reference. That cost time. I have not even a filename or a line number. Only the message that something went wrong. And all other i have to find by myself. So much time for such little mistakes. Why would Walter have a language which doesn't support good error handling?D hasn't support for unused variables, unused imports and even not for null references. Why should everyone use D instead of any other language? If i have a big project and i use many objects and one of them change to null, what now? Should the user really step through thousand lines of code because D prints only "Access Violation" without any further information? Or should i use the same principle as Java, and write every time again pre- and postconditions? I don't see any reasons why anybody should realize a big project with D and not with a other language, if the error handling and not null support remains as it is. Sorry. To reject even a such handy shorthand is incomprehensible to me.Honestly, I think that you're blowing null pointer dereferences way out proportion. In my experience, they're rare, and I have to wonder what you're doing if you're seeing them all that often. That being said, what I think we're likely to end up with is a signal handler in druntime which prints out a stacktrace when a segfault occurs (and does whatever the Windows equivalent would be on Windows). That way, you don't have to have null checks everywhere, but you still get the debug information that you need. But no one has done that yet. - Jonathan M Davis
Jul 27 2012
I also get null references (and every time i hate D a bit more), but mostly my classmates and other friends whom I've shown D. And them. If you want that D is sometimes taken seriously (and it reached only if you win more people for D), then perhaps you should do something for more usability. Such small handy shorthands are easy to implement and even more understandable as a stacktrace.
Jul 27 2012
On Friday, 27 July 2012 at 19:01:39 UTC, Namespace wrote:I also get null references (and every time I hate D a bit more), but mostly my classmates and other friends whom I've can understand them. If you want that D is sometimes taken seriously (and it reached only if you win more people for D), then perhaps you should do something for more usability. Such small handy shorthands are easy to implement and even more understandable as a stacktrace.I've noticed when debugging the 'segfault' is rather vague, but it depends on if you have something to catch it. In some of my code I end up surrounding the main function in a try/catch wrapper that prints the appropriate data; Like using VisualD. void main() { try { someFunc(null); } catch (Throwable x) { writeln(x); } } void someInnerFunc(Object o) in { assert(o, "Yo! my object's NULL!"); } body { //something } void someFunc(Object o) { someInnerFunc(o); //for stacktrace } core.exception.AssertError test.d(111): Yo! my object's NULL! ---------------- c:\Users\Era\My Documents\progs\d\test.d(119): void test.someFunc(Object) c:\Users\Era\My Documents\progs\d\test.d(103): _Dmain change inner function to: void someInnerFunc(Object o) { o.toHash; //something } object.Error: Access Violation ---------------- c:\Users\Era\My Documents\progs\d\test.d(116): void test.someFunc(Object) c:\Users\Era\My Documents\progs\d\test.d(103): _Dmain
Jul 27 2012
On Windows, an access violation (from a null pointer or other causes) is an exception that is thrown and can even be caught. On Linux, a segfault is a signal that just kills the program, it doesn't work like a regular exception. The Windows exceptions can do pretty stack traces, including on null derefs, if you have some debugging library installed... and I've done it before, but I don't remember the link right now. It's something from Microsoft.
Jul 27 2012
On Friday, 27 July 2012 at 19:48:33 UTC, Adam D. Ruppe wrote:On Windows, an access violation (from a null pointer or other causes) is an exception that is thrown and can even be caught. On Linux, a segfault is a signal that just kills the program, it doesn't work like a regular exception.Linux also dumps the state into a file. So I'd have to wonder what the problem was, you would have all the information at hand.
Jul 27 2012
On Friday, 27 July 2012 at 19:50:46 UTC, Era Scarecrow wrote:Linux also dumps the state into a file.Only if core dumps are enabled... but I think someone did a Linux stack trace signal handler somewhere for D, but it never got merged into druntime. (What it'd do is print out some info before exiting, instead of just saying "segmentation fault". Still not an exception, but a little more immediately helpful).
Jul 27 2012
On 07/27/12 21:48, Adam D. Ruppe wrote:On Windows, an access violation (from a null pointer or other causes) is an exception that is thrown and can even be caught. On Linux, a segfault is a signal that just kills the program, it doesn't work like a regular exception.It's not a regular D exception, but it is a signal that /can/ be caught and used to print stacktraces, file names, line numbers etc, not to mention you optionally get a snapshot of the program as it failed (the "core" file). The only non-trivial part is getting at the debug info to map the addresses to symbols. Simple quick and dirty example below, which will not only print the address of the instruction that caused the fault, but also the address that it tried to access, and may even sometimes succeed in letting the program continue to run. Making it work with a non-gdc compiler, non-x86 ISA, hooking up w/ a library to get all the symbol names and properly handling all the required cases is left as an exercise for the reader. :) But, no, special handling for null dereferencing in the language is *not* needed. Some more runtime support, maybe. artur import std.stdio; template Seq(alias A, alias B, S...) { static if(S.length==0) alias Seq!(A, B, A) Seq; else static if (S[$-1]!=B) alias Seq!(A, B, S, S[$-1]+1) Seq; else alias S Seq; } struct hack { import core.sys.posix.ucontext, core.sys.posix.signal; alias int c_int; static: void* av; ubyte* violator; void*[4] trace; extern (C) void handler(c_int signum, siginfo_t* si, void* _ctx ) { auto ctx = cast(ucontext_t*)_ctx; av = si._sifields._sigfault.si_addr; version (X86) enum REG_RIP = 14; violator = cast(ubyte*)ctx.uc_mcontext.gregs[REG_RIP]; ctx.uc_mcontext.gregs[REG_RIP] += inslen(violator); // scan and store backtrace etc. version (GNU) { import gcc.builtins; foreach (uint i; Seq!(0, trace.length-1)) trace[i] = __builtin_return_address(i); } checkav(); // Not something you wanna do from a signal handler... } void register() { sigaction_t sa; sa.sa_sigaction = &handler; sa.sa_flags = SA_SIGINFO; if (sigaction(SIGSEGV, &sa, null)) throw new Error("sigaction failed"); } version (X86) size_t inslen(in ubyte* c) { if (c[0]==0xc6 && c[1]==0x05) return 7; if (c[0]==0x0f && c[1]==0xb6 && c[2]==0x4b) return 4; if (c[0]==0x0f && c[1]==0xb6 && c[2]==0x43) return 4; if (c[0]==0x0f && c[1]==0xb6) return 7; if (c[0]==0xa2) return 5; if (c[0]==0x65 && c[1]==0xc7) return 11; if (c[0]==0x88 && c[1]==0x4b) return 3; // ... return 1; } auto checkav() { if (av) { writefln(" 0x%08x tried to access 0x%08x", violator, av); foreach(t; trace) writef(" 0x%08x\n", t); av = null; } } } __gshared ubyte* p = null; int main() { hack.register(); p[1] = 1; hack.checkav(); p[2] = 2; hack.checkav(); p[3] = 3; hack.checkav(); p[5] = p[4]; hack.checkav(); return p[42]; }
Jul 27 2012
And that is the explicit way with pre- and postconditions of Java, which i want to avoid. I see, the most of you prefer to write "try and catch" or use the java principle with explicit pre- and post conditions. The time will show, if D get therewith enough members to get serious.
Jul 27 2012
Me again. What's the matter if i write something for that shorthand and dmd has only to switch to it before the compiling begins? My little test program works with VisualD. I goto the build events and there i write into "Pre-Build Command": [quote]not_null main.d #t[/quote] and into "Post-Build Command": [quote]del main.d rename clone_main.d main.d[/quote] Of course i have to find a way to generate this for all included files and not do this manually as not_null a.d #t not_null b.d #t But if dmd would do this e.g. with a compiler flag like "-notnull" it would lighten my workload a lot. Here is my current example code: http://dpaste.dzfl.pl/8d41468a It replace Class? obj statements and generate two files. The normal file changes to valid D code which can compile. The "original" code with Class? obj statements will copied into clone_filename.d I know it isn't perfect, but maybe it is a beginning.
Jul 27 2012
On Saturday, July 28, 2012 01:00:22 Namespace wrote:Me again. What's the matter if i write something for that shorthand and dmd has only to switch to it before the compiling begins?Doing stuff like that makes your code completely unportable. It's _bad_ practice. Don't go and try to redesign the language if you want to be playing nice with other people. If you can do something completely within the language, then that's different (other people may still hate what you're up to, but at least they can compile it), but don't use a preprocessor unless you really don't care about anyone else ever using your code but you, and even then, I'd argue against it, because if you get into the habit of doing that, you're screwed when you actually have to interact with other D programmers. - Jonathan M Davis
Jul 27 2012
Therefore i hope that it will be official added into D. Otherwise of course i use it only for projects between me and my other students. I don't know what is wrong with this shorthand. So why don't give it a try? I'm absolutely sure that Walter will _never_ add real non-nullable references. All what will maybe come are further structs in std.alghorithm which blows up your code as assertions even do.
Jul 27 2012
I started a not null struct for phobos but then had to move, added another job, and other real life stuff that meant I haven't finished it yet. Fairly usable though. Look for struct NotNull: https://github.com/adamdruppe/phobos/blob/0c97414bb4aa3c748caa42948ffec25f8a291300/std/typecons.d (also a pull request, but for some reason, my changes to never updated here, so the pull request is out of date and temporarily closed https://github.com/D-Programming-Language/phobos/pull/477 )
Jul 27 2012
On Saturday, July 28, 2012 01:16:41 Namespace wrote:Therefore i hope that it will be official added into D. Otherwise of course i use it only for projects between me and my other students. I don't know what is wrong with this shorthand. So why don't give it a try?I don't even know what the last time I dereferenced a null pointer or null reference was. It almost never happens to me. I really think that if you're seeing very many null dererences, you're doing something fundamentally wrong with your code. At minimum, it indicates that you're not unit testing enough, since if you do that right, it'll catch the logic errors which give you null pointers/references very quickly.I'm absolutely sure that Walter will _never_ add real non-nullable references. All what will maybe come are further structs in std.alghorithm which blows up your code as assertions even do.We will get a NotNull struct at some point (probably in std.typecons). It'll statically prevent assignments from null where it can and use assertions where it can't. Adding something to the language doesn't buy you much more than that anyway. At this point, any new language feature must meet a very high bar, and if we can do it in the library instead, we will. D is incredibly powerful and is already plenty complex, so we'll take advantage of that power where we can rather than trying to change the language further. D arguably has too many features as it is. And as big a deal as you seem to think that this is, the _only_ C-based language that I'm aware of which has non-nullable references as part of the uncommon to have them, and since we can add a library type to do it, we can fix the problem without altering the language. - Jonathan M Davis
Jul 27 2012
Jonathan M Davis:Adding something to the language doesn't buy you much more than that anyway.In the case of not-nullability, this isn't true. Integrating not-null in the type system allows the language to do things you can't do with NotNull, like: // x is a nullable class reference if (x == null) { ... } else { // here the type system sees x as not null. } There are some other similar things you can't do with NotNull. In my enhancement request about not-nullability there are references to articles that explain the situation.D arguably has too many features as it is.I don't agree, the number of features is not important. What's important is how clean and intelligently they are designed, how cleanly they interact with the other features. etc.And as big a deal as you seem to think that this is, the _only_ C-based language that I'm aware of which has non-nullableThis is not true. Scala, Rust, some new Java-derived languages, and more modern languages have not nullable references. In practice I think most or all new languages coming out now have this feature. In my opinion in few years programmers will expect to have it in all languages that are not too much old and that support some kind of nullable references. Bye, bearophile
Jul 27 2012
On Saturday, July 28, 2012 01:48:00 bearophile wrote:Jonathan M Davis:??? What does it matter if the type system knows whether a pointer is null unless it's trying to warn you about dereferencing null? It's not checking for it. If we had null checks built in, that would buy you something, but we don't, and we're not going to, if nothing else because Walter is completely against it.Adding something to the language doesn't buy you much more than that anyway.In the case of not-nullability, this isn't true. Integrating not-null in the type system allows the language to do things you can't do with NotNull, like: // x is a nullable class reference if (x == null) { ... } else { // here the type system sees x as not null. }There are some other similar things you can't do with NotNull. In my enhancement request about not-nullability there are references to articles that explain the situation.There's always a cost to having more features. The more there are, the more that you have to know, and the more that it takes to learn the language. Having the features be well-designed definitely helps, and for the most part, I'm fine with the number of features that D has, but there probably are a few that ideally would be dropped but can't be at this stage (as was discussed not all that long ago in a big thread on what language features weren't useful), and adding more does come at a cost. A particular feature may be worth the cost that it brings, but the more features that you have, the more value each additional feature must bring to the table.D arguably has too many features as it is.I don't agree, the number of features is not important. What's important is how clean and intelligently they are designed, how cleanly they interact with the other features. etc.Actually, it is. I said "that I'm aware of." I didn't say that there weren't others, just that I didn't know of any others. But out of the mainstream C- based languages, it's definitely rare, much as it may be becoming less rare as new languages come along.And as big a deal as you seem to think that this is, the _only_ C-based language that I'm aware of which has non-nullableThis is not true.Scala, Rust, some new Java-derived languages, and more modern languages have not nullable references. In practice I think most or all new languages coming out now have this feature. In my opinion in few years programmers will expect to have it in all languages that are not too much old and that support some kind of nullable references.It's not necessarily a bad feature, but I do think that it's highly overrated, and regardless, there's no way that it's being added to D at this point in its life cycle. Maybe they'll be added in D3, but I wouldn't expect to see them before then at the earliest. The push right now is to use the language that we have to get things done rather than trying to constantly add features and tweak existing ones. There are probably some features that we wouldn't even have now if we had taken that approach earlier (e.g. base two literals). - Jonathan M Davis
Jul 27 2012
Jonathan M Davis:In the else branch the state of the type of x is not-null, so as example in the else branch you are allowed to call a function that only accept not null references, with the x variable. Not-nulls integrated in the type system makes sure you have well initialized variables in the class constructors in presence of inheritance and other complexities. It also statically requires you to test for null before deferencing a nullable class reference, ans so on. Those are the fruits that a good not-null implementation gives you. You can't do all this with the NotNull toy. NotNull solves only the easy part of the whole problem, and it's a small part.// x is a nullable class reference if (x == null) { ... } else { // here the type system sees x as not null. }??? What does it matter if the type system knows whether a pointer is null unless it's trying to warn you about dereferencing null?Actually, it is. I said "that I'm aware of."Right :-) Bye, bearophile
Jul 27 2012
Am Sat, 28 Jul 2012 05:07:44 +0200 schrieb "bearophile" <bearophileHUGS lycos.com>:I found this an interesting read. The implementation likely doesn't interfere much with other language features (in a sense like trusted does to templated functions that take potentially unsafe code as parameters). I especially like how the compiler _statically_ knows, that x is not null in the else case. The runtime cost is moved from every call on x, to a single if-statement! It could require a little logic to parse complex conditions like "if (a == 1 && !x != null)", though ;) -- MarcoIn the else branch the state of the type of x is not-null, so as example in the else branch you are allowed to call a function that only accept not null references, with the x variable. Not-nulls integrated in the type system makes sure you have well initialized variables in the class constructors in presence of inheritance and other complexities. It also statically requires you to test for null before deferencing a nullable class reference, ans so on. Those are the fruits that a good not-null implementation gives you. You can't do all this with the NotNull toy. NotNull solves only the easy part of the whole problem, and it's a small part. Bye, bearophile// x is a nullable class reference if (x == null) { ... } else { // here the type system sees x as not null. }
Jul 28 2012
Doing stuff like that makes your code completely unportable. It's _bad_ practice. Don't go and try to redesign the language if you want to be playing nice with other people. If you can do something completely within the language, then that's different (other people may still hate what you're up to, but at least they can compile it), but don't use a preprocessor unless you really don't care about anyone else ever using your code but you, and even then, I'd argue against it, because if you get into the habit of doing that, you're screwed when you actually have to interact with other D programmers. - Jonathan M DavisI can give them the "clone_*.d" files, which contains valid D code. No problem.
Jul 28 2012
One more question: Where can I find an official statement by Walter _why_ he does not like such shorthands? Best viewed with understandable reasons. Thanks in advance. :)
Jul 28 2012
On Fri, 27 Jul 2012 22:16:05 +0200, Namespace <rswhite4 googlemail.com> wrote:And that is the explicit way with pre- and postconditions of Java, which i want to avoid. I see, the most of you prefer to write "try and catch" or use the java principle with explicit pre- and post conditions. The time will show, if D get therewith enough members to get serious.This is a NotNull I just implemented. It is designed to create a strict division between things that can be null, and those that cannot. The idea being that the programmer should be aware of it when he needs to convert between them, and whole call graphs can more easily be made free of null checks. -- Simen
Jul 27 2012
This is a NotNull I just implemented. It is designed to create a strict division between things that can be null, and those that cannot. The idea being that the programmer should be aware of it when he needs to convert between them, and whole call graphs can more easily be made free of null checks.Foo f = new Foo(); some_function(NotNull!Foo(f)); <-explicit conversion and because it's a struct it's better to deliver it by ref. // --- Foo f = new Foo(); some_function(f); // ... void some_function(Foo f) in { assert(f !is null); } body { ^--- explicit. Unnecessary write effort. A struct as solution to avoid not null references is a bad solution. It is a nice play tool but as solution it is crap. To pack my object into a struct with ensures that it is not null, what's the difference if i use only structs and avoid classes? Why should i initialize first my object and put it then into a struct if i can even use only structs? That isn't comprehensible to me.
Jul 28 2012
On Sat, 28 Jul 2012 10:20:56 +0200, Namespace <rswhite4 googlemail.com> wrote:The conversion from a pointer to a struct containing a pointer should be without cost when compiling with optimizations on. The effect is exactly the same as with a pointer, which I hope you don't habitually pass by reference.This is a NotNull I just implemented. It is designed to create a strict division between things that can be null, and those that cannot. The idea being that the programmer should be aware of it when he needs to convert between them, and whole call graphs can more easily be made free of null checks.Foo f = new Foo(); some_function(NotNull!Foo(f)); <-explicit conversion and because it's a struct it's better to deliver it by ref.A struct as solution to avoid not null references is a bad solution. It is a nice play tool but as solution it is crap. To pack my object into a struct with ensures that it is not null, what's the difference if i use only structs and avoid classes? Why should i initialize first my object and put it then into a struct if i can even use only structs? That isn't comprehensible to me.Huh? I believe you have misunderstood something here. The struct is a form of smart pointer. It behaves like a pointer does, and lets you have polymorphism, inheritance and all that stuff that comes with classes. Granted, I have found a few issues with the version I posted (mostly to do with subclassing). Most have been fixed in this version, but some are unfixable until issue 1528 has been resolved. -- Simen
Jul 28 2012
Huh? I believe you have misunderstood something here. The struct is a form of smart pointer. It behaves like a pointer does, and lets you have polymorphism, inheritance and all that stuff that comes with classes. Granted, I have found a few issues with the version I posted (mostly to do with subclassing). Most have been fixed in this version, but some are unfixable until issue 1528 has been resolved.Some kind of smart pointer is easy to write, or not? What's wrong with this? http://dpaste.dzfl.pl/11a4d692
Jul 28 2012
On Fri, 27 Jul 2012 17:35:19 +0200, Jonathan M Davis <jmdavisProg gmx.com> wrote:Many of us think that const Foo func() {} should just become illegal inconsistency or not because of all of this confusion, but Walter doesn't buy into that.Like monarch_dodra said, this is also a style favored by some: pure property const int foo() { //... } Having to write that pure property int foo() const { //... } at the very least feels weird. int foo() const pure property { } could work, I guess. But it feels backward. -- Simen
Jul 27 2012
On Friday, July 27, 2012 19:34:52 Simen Kjaeraas wrote:On Fri, 27 Jul 2012 17:35:19 +0200, Jonathan M Davis <jmdavisProg gmx.com> wrote:Personally, I _always_ put the attributes on the right-hand side save for the ones which exist in C++ and Java (which is pretty much just the access specifiers, static, override, and final), and I think that it's ugly and confusing to have them on the left, but that's a matter of personal preference. const on the other hand constantly causes issues because - unlike the others - it can be applied to the return type as well. And the question comes up often enough that I think that it's a real problem and one that merits making putting it on the left illegal. At minimum, making it illegal on the left without other attributes between it and the return type should be illegal IMHO (though that could cause even more confusion depending on the error message, since then it might be confusing why you could put it on the left but only in some positions). That change isn't going to happen at this point, but I think that we'd be better off if it were. - Jonathan M DavisMany of us think that const Foo func() {} should just become illegal inconsistency or not because of all of this confusion, but Walter doesn't buy into that.Like monarch_dodra said, this is also a style favored by some: pure property const int foo() { //... } Having to write that pure property int foo() const { //... } at the very least feels weird. int foo() const pure property { } could work, I guess. But it feels backward.
Jul 27 2012