www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A few questions

reply "Namespace" <rswhite4 googlemail.com> writes:
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
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
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
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-07-27 13:14, Jacob Carlborg wrote:
 On 2012-07-27 12:29, Namespace wrote:
 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 () {} }
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 Carlborg
Jul 27 2012
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
 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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Friday, 27 July 2012 at 11:50:46 UTC, bearophile wrote:
 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
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.
Jul 27 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Fri, 27 Jul 2012 14:44:35 +0200, bearophile <bearophileHUGS lycos.com>  
wrote:

 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
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. -- Simen
Jul 27 2012
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
parent "Namespace" <rswhite4 googlemail.com> writes:
Short improvement: http://dpaste.dzfl.pl/f3263def
Jul 27 2012
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
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
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 07/27/2012 04:35 PM, bearophile wrote:
 But implementing good non-null types in library code is hard
It 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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 07/29/2012 06:24 PM, bearophile wrote:
 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?
Google for "freedom before commitment". The example is in the paper. Apparently the unsoundness was recently fixed though -- the faulty compiler.
Jul 29 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
parent reply "Namespace" <rswhite4 googlemail.com> writes:
 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
That 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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, July 27, 2012 20:07:56 Namespace wrote:
 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
That 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?
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.
 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
parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
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
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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
next sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
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
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
prev sibling parent Artur Skawina <art.08.09 gmail.com> writes:
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
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
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
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
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
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
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-nullable

This 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
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, July 28, 2012 01:48:00 bearophile wrote:
 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. }
??? 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.
 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.
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.
 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

This is not true.
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.
 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
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 // 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?
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.
 Actually, it is. I said "that I'm aware of."
Right :-) Bye, bearophile
Jul 27 2012
parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sat, 28 Jul 2012 05:07:44 +0200
schrieb "bearophile" <bearophileHUGS lycos.com>:

 // x is a nullable class reference
 if (x == null) {
      ...
 } else {
      // here the type system sees x as not null.
 }
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. Bye, bearophile
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 ;) -- Marco
Jul 28 2012
prev sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
 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
I can give them the "clone_*.d" files, which contains valid D code. No problem.
Jul 28 2012
parent "Namespace" <rswhite4 googlemail.com> writes:
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
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
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
parent reply "Namespace" <rswhite4 googlemail.com> writes:
 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
parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Sat, 28 Jul 2012 10:20:56 +0200, Namespace <rswhite4 googlemail.com>  
wrote:

 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.
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.
 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
parent "Namespace" <rswhite4 googlemail.com> writes:
 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
prev sibling next sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
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
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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:
 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.
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 Davis
Jul 27 2012