Re: float[] → Vertex[] – decreases performance by 1000%
Am 26.07.2012 21:18, schrieb David: Hm. Do you ever do pointer arithmetic on Vertex*? Is the size and offsets are correct (like in Vertex vs float)? No, yes. I really have no idea why this happens, I saved the contents of my buffers and compared them with the buffers of the `float[]` version (thanks to `git checkout`) and they were exactly 100% the same. It's a mystery. can you create a version of you code thats allows switching (version(Vertex) else ...) between array and Vertex? or provide both versions here again you checked dmd and ldc output so it can't be a backend thing (maybe frontend or GC) - or mysterious GL bugs
Re: Writing very large files 50+ GB
On Fri, 27 Jul 2012 02:50:56 +0100, wmunger wmun...@gmail.com wrote: I need to write to a file that is 50 to 250GB on all three major operating systems. I tried to use the c function pwrite64. But it is not available on the Mac. I have seen where some have used the iostream in C++ but this does not seem to work on the Mac. Is there any way to write in D very large files. After all I would rather write in D than wrap C or C++ code. Have you looked for open, lseek(64) and write? R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Assert prints an array of char when used why to!string
Code: import std.conv; void main() { static assert( is(typeof((Failure: ~ to!string(55)) == string)) ); static assert(0 , (Failure: ~ to!string(55))); } main.d(7): Error: static assert ['F','a','i','l','u','r','e',':',' ','5','5'] The problem is the ugly-ass print as array of individual characters. I really don't understand what is going on, since the compile type of my string is indeed string. If I remove the to!string, I get: main.d(7): Error: static assert Failure 1) Is this the normal behavior, or a known limitation? 2) Is there a workaround? FYI, this was originally produced by code from Phobos, but was trimmed by me here.
A few questions
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.
Re: A few questions
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.
Re: A few questions
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
Re: A few questions
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
Re: A few questions
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. :)
Re: A few questions
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
Re: Assert prints an array of char when used why to!string
monarch_dodra: 1) Is this the normal behavior, or a known limitation? It seems a DMD bug, why don't you add it to Bugzilla? 2) Is there a workaround? static assert(0, text(Failure: , 55)); Bye, bearophile
Re: A few questions
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.
Re: A few questions
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
Re: A few questions
On Fri, 27 Jul 2012 14:44:35 +0200, bearophile bearophileh...@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
Re: A few questions
Short improvement: http://dpaste.dzfl.pl/f3263def
Re: A few questions
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 what Spec# shows good non-null types are meant to be. Bye, bearophile
Re: A few questions
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?
Re: Assert prints an array of char when used why to!string
BTW, in docs about text: http://dlang.org/phobos/std_conv.html#text ...Convenience functions for converting any number and types of arguments into text (the three character widths)... What is the three character widths note? Who knows?
Re: Assert prints an array of char when used why to!string
On Friday, 27 July 2012 at 14:40:33 UTC, novice2 wrote: What is the three character widths note? Who knows? string, wstring, and dstring. Width refers to the bit size of the char (8 bit, 16 bit, or 32 bit).
Re: Assert prints an array of char when used why to!string
Ah, thanks! On Friday, 27 July 2012 at 14:47:49 UTC, Adam D. Ruppe wrote: On Friday, 27 July 2012 at 14:40:33 UTC, novice2 wrote: What is the three character widths note? Who knows? string, wstring, and dstring. Width refers to the bit size of the char (8 bit, 16 bit, or 32 bit).
Re: A few questions
On Fri, 27 Jul 2012 16:39:49 +0200, Namespace rswhi...@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
Just a matter of parentheses
This works in DMD 2.059, but it doesn't in dmd 2.060beta: import std.algorithm: sort; void main() { int[int] foo; auto bar1 = foo.keys().sort(); // OK auto bar2 = foo.keys.sort(); // Error: function expected before ()... } Do you think this should be filed as regression? Bye, bearophile
Re: Just a matter of parentheses
On 27-07-2012 17:23, bearophile wrote: This works in DMD 2.059, but it doesn't in dmd 2.060beta: import std.algorithm: sort; void main() { int[int] foo; auto bar1 = foo.keys().sort(); // OK auto bar2 = foo.keys.sort(); // Error: function expected before ()... } Do you think this should be filed as regression? Bye, bearophile Yes. keys is specifically meant to be a property. -- Alex Rønne Petersen a...@lycus.org http://lycus.org
Re: A few questions
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
A matter of inout
This program used to compile in DMD 2.059: import std.stdio; inout(T[]) forwardDifference(T)(inout(T[]) s, in int n) pure { foreach (_; 0 .. n) s[] -= s[1 .. $]; return s[0 .. $-n]; } void main() { immutable A = [90.5, 47, 58, 29, 22, 32, 55, 5, 55, 73.5]; foreach (level; 0 .. A.length) writeln(forwardDifference(A.dup, level)); } Now it gives: test.d(5): Error: slice s[] is not mutable test.d(12): Error: template instance test.forwardDifference!(double) error instantiating Is it a 2.060 regression (or it's caused by a bug fix)? Bye, bearophile
Re: Assert prints an array of char when used why to!string
On Friday, 27 July 2012 at 11:56:07 UTC, bearophile wrote: monarch_dodra: 1) Is this the normal behavior, or a known limitation? It seems a DMD bug, why don't you add it to Bugzilla? 2) Is there a workaround? static assert(0, text(Failure: , 55)); Bye, bearophile Thanks. I'll create an entry in bugzilla.
Re: Just a matter of parentheses
Alex Rønne Petersen: Yes. keys is specifically meant to be a property. http://d.puremagic.com/issues/show_bug.cgi?id=8453 Bye, bearophile
copying the targets of pointers
This is going to sound stupid, but how do you have two pointers' targets copy each other? since pointers are used like reference types, how do you write the C++ equivalent of *p1 == *p2 Here is the context of what I'm trying to do: struct S { struct Payload {} Payload payload; @property typeof(this) dup() { typeof(this) ret; if(payload) { ret.payload = new Payload; ret.payload = payload; //Copies the payload? The pointer? } return ret; } } So yeah, that was my question. I'd be tempted to write: ret.payload.field1 = payload.field1; ret.payload.field2 = payload.field2; ... But: 1) It feels hackish and just going around the problem 2) It works for pointer to Struct with fields, but what about things like int* ? Oh yeah, also, if you have a better idea for an better (cleaner) implementation of a payload based reference type structs, I'm all ears.
Re: A matter of inout
On 27-Jul-12 19:53, bearophile wrote: This program used to compile in DMD 2.059: import std.stdio; inout(T[]) forwardDifference(T)(inout(T[]) s, in int n) pure { foreach (_; 0 .. n) s[] -= s[1 .. $]; return s[0 .. $-n]; } void main() { immutable A = [90.5, 47, 58, 29, 22, 32, 55, 5, 55, 73.5]; foreach (level; 0 .. A.length) writeln(forwardDifference(A.dup, level)); } Now it gives: test.d(5): Error: slice s[] is not mutable test.d(12): Error: template instance test.forwardDifference!(double) error instantiating Is it a 2.060 regression (or it's caused by a bug fix)? If it compiled before then I'd think it's a regression. -- Dmitry Olshansky
Re: A matter of inout
On 07/27/12 17:53, bearophile wrote: This program used to compile in DMD 2.059: import std.stdio; inout(T[]) forwardDifference(T)(inout(T[]) s, in int n) pure { foreach (_; 0 .. n) s[] -= s[1 .. $]; return s[0 .. $-n]; } void main() { immutable A = [90.5, 47, 58, 29, 22, 32, 55, 5, 55, 73.5]; foreach (level; 0 .. A.length) writeln(forwardDifference(A.dup, level)); } Now it gives: test.d(5): Error: slice s[] is not mutable test.d(12): Error: template instance test.forwardDifference!(double) error instantiating Is it a 2.060 regression (or it's caused by a bug fix)? 'inout' basically means 'local const' - if you'd allow inout data to be modified then it wouldn't be possible to call the function with a const or immutable argument - which is the whole point of inout... You probably want 'inout(T)[]' if you're going to alter the array. artur
Re: copying the targets of pointers
On 07/27/12 18:11, monarch_dodra wrote: This is going to sound stupid, but how do you have two pointers' targets copy each other? since pointers are used like reference types, how do you write the C++ equivalent of *p1 == *p2 Exactly the same, there's no difference between C and D pointers, except for classes. Here is the context of what I'm trying to do: struct S { struct Payload {} Payload payload; @property typeof(this) dup() { typeof(this) ret; if(payload) { ret.payload = new Payload; ret.payload = payload; //Copies the payload? The pointer? 'ret.payload' is 'S'; 'new Payload' is '*S'... If you meant 'Payload* payload;', then just the pointer is copied. artur
Re: A matter of inout
Artur Skawina: 'inout' basically means 'local const' - if you'd allow inout data to be modified then it wouldn't be possible to call the function with a const or immutable argument - which is the whole point of inout... You probably want 'inout(T)[]' if you're going to alter the array. Using inout(T)[] gives the same error: import std.stdio; inout(T)[] forwardDifference(T)(inout(T)[] s, in int n) pure { foreach (_; 0 .. n) s[] -= s[1 .. $]; return s[0 .. $ - n]; } void main() { immutable A = [90.5, 47, 58, 29, 22, 32, 55, 5, 55, 73.5]; foreach (level; 0 .. A.length) writeln(forwardDifference(A.dup, level)); } Bye, bearophile
Re: A matter of inout
Artur Skawina: 'inout' basically means 'local const' - if you'd allow inout data to be modified then it wouldn't be possible to call the function with a const or immutable argument - which is the whole point of inout... dmd 2.059 was wrong then. Bye, bearophile
Re: A matter of inout
On 07/27/12 19:06, bearophile wrote: Artur Skawina: 'inout' basically means 'local const' - if you'd allow inout data to be modified then it wouldn't be possible to call the function with a const or immutable argument - which is the whole point of inout... You probably want 'inout(T)[]' if you're going to alter the array. Using inout(T)[] gives the same error: import std.stdio; inout(T)[] forwardDifference(T)(inout(T)[] s, in int n) pure { foreach (_; 0 .. n) s[] -= s[1 .. $]; return s[0 .. $ - n]; } void main() { immutable A = [90.5, 47, 58, 29, 22, 32, 55, 5, 55, 73.5]; foreach (level; 0 .. A.length) writeln(forwardDifference(A.dup, level)); } This alters not only the array, but also modifies the elements. Using just 'T' instead of 'inout(T)' will do the right thing; why would you like to use inout in cases like this one? 'inout' allows you to not write two or more /identical/ function bodies when the code can deal with immutable/const/mutable; functions that modify the data in-place obviously can't do that. artur
Re: copying the targets of pointers
On Friday, 27 July 2012 at 16:47:47 UTC, Artur Skawina wrote: On 07/27/12 18:11, monarch_dodra wrote: This is going to sound stupid, but how do you have two pointers' targets copy each other? since pointers are used like reference types, how do you write the C++ equivalent of *p1 == *p2 Exactly the same, there's no difference between C and D pointers, except for classes. Here is the context of what I'm trying to do: struct S { struct Payload {} Payload payload; @property typeof(this) dup() { typeof(this) ret; if(payload) { ret.payload = new Payload; ret.payload = payload; //Copies the payload? The pointer? 'ret.payload' is 'S'; 'new Payload' is '*S'... If you meant 'Payload* payload;', then just the pointer is copied. artur Dang it, yes, I meant: struct Payload {} Payload* payload; And I want to copy the value pointed by payload. Not the pointer. I'm kind of confused, because every time I see pointer usage, the deference operator is omitted? For example: struct S { void foo(){}; } S* p = new S(); p.foo(); When and where can/should/shouldn't I dereference?
Re: A matter of inout
On 07/27/2012 10:13 AM, bearophile wrote: Artur Skawina: 'inout' basically means 'local const' - if you'd allow inout data to be modified then it wouldn't be possible to call the function with a const or immutable argument - which is the whole point of inout... dmd 2.059 was wrong then. I think so. I have understood that aspect of inout recently: since the function is not a template (bear with me please! I know it is a template here :)), there will be a single instance of it. Since that instance must work with mutable and immutable, the parameter cannot be modified inside the function. Even if the function is never called with immutable, the compiler must compile the code as if 'inout' is spelled as 'const'. The above makes sense for a regular function. I guess the guideline here is not to use inout on a template parameter as it doesn't make sense because T carries that information anyway. Ali
Re: copying the targets of pointers
On 07/27/2012 09:11 AM, monarch_dodra wrote: This is going to sound stupid, but how do you have two pointers' targets copy each other? since pointers are used like reference types, how do you write the C++ equivalent of *p1 == *p2 The type must provide a function to make a copy of itself. Since arrays have .dup, that may be a suitable name: auto newObject = object.dup; Ali
Re: A few questions
On Fri, 27 Jul 2012 17:35:19 +0200, Jonathan M Davis jmdavisp...@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
Re: Assert prints an array of char when used why to!string
On 07/27/2012 09:02 AM, monarch_dodra wrote: On Friday, 27 July 2012 at 11:56:07 UTC, bearophile wrote: monarch_dodra: 1) Is this the normal behavior, or a known limitation? It seems a DMD bug, why don't you add it to Bugzilla? 2) Is there a workaround? static assert(0, text(Failure: , 55)); Bye, bearophile Thanks. I'll create an entry in bugzilla. Thanks. I hope that will fix the Unicode ignorance of 'static assert' as well: static assert(false, aüz); produces the following output: Error: static assert a\xc3\xbcz Ali
Re: copying the targets of pointers
On Fri, 27 Jul 2012 19:28:06 +0200, monarch_dodra monarchdo...@gmail.com wrote: I'm kind of confused, because every time I see pointer usage, the deference operator is omitted? For example: struct S { void foo(){}; } S* p = new S(); p.foo(); When and where can/should/shouldn't I dereference? Whenever you need to. :p Instead of having both . and -, D has only ., and it derefences for you, when it needs to. In terms of other D features, we could imagine pointers being implemented thus: struct Pointer(T) { T* payload; // Yes, it's a pointer. I *could* use some other // type and reinterpret_cast it, but I won't. :p @property ref T get() { return *payload; } alias get this; // Add operator overloading and all sorts of other magic here. } This also means that (*foo).bar() is exactly the same as foo.bar(). The only times you need to derefence is when you need direct access to the pointee, not just its members. That usually means when you pass it as a parameter, but also when you have multiple indirections, or if you're going bit-fiddling. -- Simen
Re: A few questions
On Friday, July 27, 2012 19:34:52 Simen Kjaeraas wrote: On Fri, 27 Jul 2012 17:35:19 +0200, Jonathan M Davis jmdavisp...@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
Re: copying the targets of pointers
On Friday, July 27, 2012 10:32:07 Ali Çehreli wrote: On 07/27/2012 09:11 AM, monarch_dodra wrote: This is going to sound stupid, but how do you have two pointers' targets copy each other? since pointers are used like reference types, how do you write the C++ equivalent of *p1 == *p2 The type must provide a function to make a copy of itself. Since arrays have .dup, that may be a suitable name: auto newObject = object.dup; That's only if you're dealing with references or if the pointers point to structs which are reference types (or if they're pointers to arrays, which would be a bit weird). If you're dealing with a built-in type or value type structs, then no dup is necessary. - Jonathan M Davis
Re: A few questions
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.
Re: A few questions
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
Re: copying the targets of pointers
On 07/27/12 19:28, monarch_dodra wrote: On Friday, 27 July 2012 at 16:47:47 UTC, Artur Skawina wrote: On 07/27/12 18:11, monarch_dodra wrote: This is going to sound stupid, but how do you have two pointers' targets copy each other? since pointers are used like reference types, how do you write the C++ equivalent of *p1 == *p2 Exactly the same, there's no difference between C and D pointers, except for classes. Here is the context of what I'm trying to do: struct S { struct Payload {} Payload payload; @property typeof(this) dup() { typeof(this) ret; if(payload) { ret.payload = new Payload; ret.payload = payload; //Copies the payload? The pointer? 'ret.payload' is 'S'; 'new Payload' is '*S'... If you meant 'Payload* payload;', then just the pointer is copied. artur Dang it, yes, I meant: struct Payload {} Payload* payload; And I want to copy the value pointed by payload. Not the pointer. Payload* p = new Payload; *ret.payload = *p; or just *ret.payload = *new Payload; I'm kind of confused, because every time I see pointer usage, the deference operator is omitted? For example: struct S { void foo(){}; } S* p = new S(); p.foo(); When and where can/should/shouldn't I dereference? The C '.' and '-' operators are folded into just one D op -- the '.'. So everywhere where you'd write 'p-foo' in C/C++ you just do 'p.foo' in D. Since both '-' and '.' C ops wouldn't make sense in the same context, the compiler will do the right thing automagically. artur
Re: A few questions
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 most of them are already back to C++ or C#. And I 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.
Re: A few questions
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 shown D. And most of them are already back to C++ or C#. And I 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
Re: A few questions
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.
Re: A few questions
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.
Re: A few questions
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).
Re: A few questions
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. But this is what Java and C# have already.
Re: A few questions
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]; }
Implementing a Monitor
I'm using condition variables to implement a monitor that simulates the producer-consumer(unbounded buffer) scenario. Note: monitor is __gshared and is initialized in main(). Then the other threads are created and run. There is one producer thread, and 5 consumer threads. void producer() { while( 1 ) { monitor.produce(); } } void consumer() { while( 1 ) { monitor.consume(); } } class Monitor { Cond cond; char[] buffer; ulong sz; this() { // necessary: The condition variable constructor requires a mutex passed to it cond = new Cond(new Mutex()); } void produce() { // produce a letter a-z char c = 'a' + rand() % 26; writeln(* Producer: Produced a ', c, ' buffer.length = , buffer.length, \n); // put it into the buffer ++buffer.length; buffer[buffer.length - 1] = c; //if( buffer.length 1 ) notify(cond); // calls condition.notify() //Thread.sleep(dur!msecs(1000)); } void consume() { if( buffer.length == 0 ) { writeln(put to sleep); cwait(cond); // calls Condition.wait() } // take char c = buffer[buffer.length-1]; --buffer.length; writeln(# Consumer has taken a ', c, ' buffer = [, buffer, ] (, buffer.length, elements)\n); } } The output is something like: put to sleep put to sleep put to sleep put to sleep * Producer: Produced a 'n' buffer.length = 0 put to sleep * Producer: Produced a 'w' buffer.length = 1 * Producer: Produced a 'l' buffer.length = 2 * Producer: Produced a 'r' buffer.length = 3 * Producer: Produced a 'b' buffer.length = 4 * Producer: Produced a 'b' buffer.length = 5 * Producer: Produced a 'm' buffer.length = 6 * Producer: Produced a 'q' buffer.length = 7 ... Even though the producer calls notify() when he finishes, none of the consumer threads is ever resumed... (I ran the program for a while and redirected output to a file. Then I searched for # that the consumer prints but nothing). Why is that happening? Is there something wrong with Condition.notify()? Also, is there a function that I can call to immediatly suspend the running thread? Thanks
Re: A few questions
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.
Re: A few questions
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
Re: A few questions
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.
Re: A few questions
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 )
Re: A few questions
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 language is C#. So, while they may have their uses, it's actually very 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
Re: A few questions
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 references as part of the language is C#. 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
Re: A few questions
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