Dynamic multidimensional arrays
Can anyone point me in the right direction for doing something like this in D: char[][] anArray; int rows, cols; ... anArray = new char[rows][cols]; It isn't possible in this way because rows cannot be read at compile time, which seems to me to be the point of dynamic arrays. :P
Re: Using a C function with command line parameters
On 2011-07-04 18:59, Steven Schveighoffer wrote: On Mon, 04 Jul 2011 12:51:48 -0400, Jacob Carlborg d...@me.com wrote: On 2011-07-04 16:31, Jonathan Sternberg wrote: glut has the function: void glutInit( int* pargc, char** argv ); In order to use it. Since D has an ABI compatible with C, I should be able to write a D file with extern (C) on the glut functions. How would I wrap this function to be used with D arrays? Such as: int main(string[] args) { glutInit( /* I don't know what to do here */ ); return 0; } Thanks. It depends on what your needs are. If your not actually using the arguments then you can pass in 0 and null, or 1 and the name of the application. A typical library that uses standardized arguments (i.e. parameters that always mean the same thing across applications that use that library) has a parameter pre-processing function such as this which consume their specific arguments from the command line. The idea is, you pass the command line to those functions, the library processes its specific arguments, removing them from the command line array, and then all applications using that library have a way to control the library from the command line. I think the first one I remember having this is X and Xt. For example, most X-based applications you can pass --display=mysystem:0 and it uses that display. The applications simply use a libX function that processes those args from the command line and never have to deal with it. As an alternative, most platforms have an API for getting the arguments passed to an application. Mac OS X: extern (C) char*** _NSGetEnviron(); Posix: extern (C) extern char** environ; Those get the environment variables, not the command line arguments. Hehe. Wonder what I was thinking. Anyway, the platforms usually do have an API for that, second try: Mac OS X: extern(C) char*** _NSGetArgv(); extern(C) int* _NSGetArgc(); Linux: I read somewhere you could read from /proc/pid/cmdline Where pid is the process id. Don't know about Windows. Windows actually does have a command line fetching function. Can't remember what it is, but if I had to guess I'd say it was GetCommandLine :) -Steve Seems to be that one. -- /Jacob Carlborg
Re: Dynamic multidimensional arrays
On 2011-07-04 23:42, Bellum wrote: Can anyone point me in the right direction for doing something like this in D: char[][] anArray; int rows, cols; ... anArray = new char[rows][cols]; It isn't possible in this way because rows cannot be read at compile time, which seems to me to be the point of dynamic arrays. :P auto anArray = new char[][](rows, cols); Putting the numbers directly in the brackets tries to create a static array once you get beyond the first dimension. So, auto anArary = new char[4][5]; would create a dynamic array of length for with elements which are static arrays of length 5. If you want it to by dynamic all the way, you need to put the dimensions in the parens like above. Personally, I _never_ put them in the brackets, even when the dynamic array has just one dimension. It's just simpler to always put them in the parens and not worry about it. - Jonathan M Davis
Re: Dynamic multidimensional arrays
On 2011-07-04 23:56, Jonathan M Davis wrote: On 2011-07-04 23:42, Bellum wrote: Can anyone point me in the right direction for doing something like this in D: char[][] anArray; int rows, cols; ... anArray = new char[rows][cols]; It isn't possible in this way because rows cannot be read at compile time, which seems to me to be the point of dynamic arrays. :P auto anArray = new char[][](rows, cols); Putting the numbers directly in the brackets tries to create a static array once you get beyond the first dimension. So, auto anArary = new char[4][5]; would create a dynamic array of length for with elements which are static arrays of length 5. If you want it to by dynamic all the way, you need to put the dimensions in the parens like above. Personally, I _never_ put them in the brackets, even when the dynamic array has just one dimension. It's just simpler to always put them in the parens and not worry about it. Correction, auto anArray = new char[4][5]; would create a dynamic array of length 5 of static arrays with length 4, though auto anArray = new char[][](4, 5); does create a dynamic array of length 4 of dynamic arrays of length 5. It quickly gets confusing when dealing with dimensions and static arrays IMHO. - Jonathan M Davis
Re: Dynamic multidimensional arrays
Jonathan M Davis Wrote: It quickly gets confusing when dealing with dimensions and static arrays IMHO. I agree. I have raised this topic time ago with no results so far. I find it surprising that Walter Andrei too don't think of this as confusing :-| Bye, bearophile
Re: void.sizeof == 1, not 0
On 01.07.2011 22:18, Ali Çehreli wrote: On Fri, 01 Jul 2011 21:18:45 +0200, simendsjo wrote: What is contained within this byte? (T[0]).sizeof == 0, why isn't void also 0? void* can point to any data, in which case it is considered to be pointing at the first byte of the data. Having a size of one makes it point to the next byte when incremented: int i; void * v =i; // first byte ++v; // second byte Similarly, an empty struct has a size of one: import std.stdio; struct S {} void main() { assert(S.sizeof == 1); } But in that case it is needed to identify S objects from one another just by having different addresses. The following array's data will occupy 10 bytes: S[10] objects; assert((objects[0]) !=(objects[1])); Ali Needed some time to digest your answer, but it makes sense now. Thanks.
Re: Using a C function with command line parameters
On Tue, 05 Jul 2011 00:29:14 -0400, Jonathan Sternberg jonathansternb...@gmail.com wrote: It's one of the applications that consumes command line arguments. So if I wanted to implement this, a copy of the D strings (and null terminated) would have to be made. I would also likely need to add another slot to the command line arguments as usually the command line is null terminated for C programs. Generally, command line arguments don't modify the parameters. But C isn't particularly good at using const correctness. A wrapper around glutInit would require copying the array to a C-style array, calling the extern (C)'d function, then copying back the changes to the D side back to a D style array. Right? Yes, probably the best thing to do. -Steve
Re: Operator Overloading and boilerplate code
On 2011-07-05 03:11, Ali Çehreli wrote: On Tue, 05 Jul 2011 02:44:03 +0200, Loopback wrote: I've researched a bit though I still haven't come up with a solution. Since the problem lies within (the most simple) constructor, I tried to modify it for another outcome. If I supplied a generic parameter to the pre-constructor the Cannot evaluate at compile time message disappeared but two new errors appeared instead. This is what I modified: this()(float x, float y, float z) = this(T)(float x, float y, float z) If I use this code instead, I get two other errors appearing: Error: template test.DVECTOR2.__ctor(T) does not match any function template declaration This error and another one (individual to each statement) appears in the following code statements: Error: template test.DVECTOR2.__ctor(T) cannot deduce template function from argument types !()(float,float) DVECTOR2 m_zoom = DVECTOR2(2f, 2f); Error: template test.DVECTOR2.__ctor(T) cannot deduce template function from argument types !()(immutable(float),const(float)) immutable DVECTOR2 m_UP_DIR = DVECTOR2(0f, 1f, 0f); Here is a simple form of the same problem: struct S { this(T)(double d) {} } void main() { auto o = S(1.5); } Error: template deneme.S.__ctor(T) does not match any function template declaration Error: template deneme.S.__ctor(T) cannot deduce template function from argument types !()(double) The compiler is right: What should T be there? int? string? MyClass? I've realized again that I don't know how to specify the template parameter for the constructor. The following attempt fails as the compiler thinks S itself is a template: auto o = S!string(1.5); Error: template instance S is not a template declaration, it is a struct And if I try to be smart after the error message, this seg faults the compiler: auto o = S.__ctor!string(1.5); Ali Hmm... Interesting. Thank you for clarifying and explaining that! I guess supplying T to the constructor when the parameters are already known to avoid compiler errors is not a solution then. Seems to me as if its only aggravates things. Though is there no solution nor any workarounds for this problem? I've attempted to use two different types of constructors and both appeared to be very limited, and I do not believe that this is the case. If you use a generic constructor is there no possible way to use it in cases where immutable and const is involved? Or is there a page that I have missed perhaps? struct DVECTOR2 { // Controls that the parameter is a valid type template Accepts(T) { enum Accepts = is(T == DVECTOR2) || is(T == float) || is(T == D3DXVECTOR2) || is(T == POINT); } // Whether the parameter is a float or not template isScalar(T) { enum isScalar = is(T == float); } // The Variables float x = 0f; float y = 0f; // Default Constructor this()(float x, float y) { this.x = x; this.y = y; } // Float Constructor this()(float xy) { this(xy, xy); } // Implement D3DXVECTOR2 and POINT support this(T)(T arg) if(Accepts!T !isScalar!T) { this(arg.tupleof); } // Inverse the vector DVECTOR2 opUnary(string op)() if(op == -) { return DVECTOR2(-x, -y); } // Binary Operations DVECTOR2 opBinary(string op, T)(T rhs) if(Accepts!T) { enum rx = isScalar!T ? : .x; enum ry = isScalar!T ? : .y; return DVECTOR2(mixin(x ~ op ~ rhs ~ rx), mixin(y ~ op ~ rhs ~ ry)); } // Right Binary Operator DVECTOR2 opBinaryRight(string op, T)(T lhs) if(Accepts!T) { return DVECTOR2(lhs).opBinary!op(this); } // Assign Operator ref DVECTOR2 opAssign(T)(T rhs) if(Accepts!T) { static if(isScalar!T) x = y = rhs; else { x = rhs.x; y = rhs.y; } return this; } // In-Place Assignment Operators ref DVECTOR2 opOpAssign(string op, T)(T rhs) if(Accepts!T) { return(this.opAssign(opBinary!op(rhs))); } // Cast Operators (to D3DXVECTOR2 and POINT) T opCast(T)() if(Accepts!T !isScalar!T) { return T(x, y); } } unittest { // This fails, saying that the expression cannot be // evaluated at compile time. immutable DVECTOR2 test = DVECTOR2(0f, 1f, 0f); }
Re: Operator Overloading and boilerplate code
On Tue, 05 Jul 2011 16:20:44 +0200, Loopback wrote: On 2011-07-05 03:11, Ali Çehreli wrote: struct S { this(T)(double d) {} } void main() { auto o = S(1.5); } Error: template deneme.S.__ctor(T) does not match any function template declaration Error: template deneme.S.__ctor(T) cannot deduce template function from argument types !()(double) The compiler is right: What should T be there? int? string? MyClass? I've realized again that I don't know how to specify the template parameter for the constructor. The following attempt fails as the compiler thinks S itself is a template: auto o = S!string(1.5); Error: template instance S is not a template declaration, it is a struct And if I try to be smart after the error message, this seg faults the compiler: auto o = S.__ctor!string(1.5); Ali Hmm... Interesting. Thank you for clarifying and explaining that! I guess supplying T to the constructor when the parameters are already known to avoid compiler errors is not a solution then. Seems to me as if its only aggravates things. Though is there no solution nor any workarounds for this problem? I've attempted to use two different types of constructors and both appeared to be very limited, and I do not believe that this is the case. I don't want to look like brushing off the problem but having many constructors make the code complicated. For example, it may be confusing which constructor gets called here: auto d = DVECTOR2(1.5); Are we setting just x or both x and y? Especially when we know that DVECTOR2 is a struct and that structs have this feature of assigning default values to the trailing unspecified members (at least in some cases), I think a factory function would be better in this case: auto d = square_DVECTOR2(1.5); Now we know that both x and y will be 1.5. Same can be said for some of the other constructors. It is not difficult at all for the caller to give us what we want; and it is clearer: D3DXVECTOR2 d3; // ... auto d = DVECTOR2(d3.tupleof); (I think this is in line with Kevlin Henney's Parameterize from Above guideline/pattern/idiom/etc. :)) If you use a generic constructor is there no possible way to use it in cases where immutable and const is involved? Or is there a page that I have missed perhaps? D2 has changed the meaning of inout to mean something like templatize just the mutable/const/immutable qualification of the parameter but it is not implemented fully yet. Look at Inout Functions on the Functions spec: http://d-programming-language.org/function.html struct DVECTOR2 { // Controls that the parameter is a valid type template Accepts (T) { enum Accepts = is(T == DVECTOR2) || is(T == float) || is(T == D3DXVECTOR2) || is(T == POINT); } // Whether the parameter is a float or not template isScalar(T) { enum isScalar = is(T == float); } // The Variables float x = 0f; float y = 0f; // Default Constructor this()(float x, float y) { this.x = x; this.y = y; } // Float Constructor this()(float xy) { this(xy, xy); } // Implement D3DXVECTOR2 and POINT support this(T)(T arg) if (Accepts!T !isScalar!T) { this(arg.tupleof); } Ali
Re: Operator Overloading and boilerplate code
On 2011-07-05 18:05, Ali Çehreli wrote: I don't want to look like brushing off the problem but having many constructors make the code complicated. For example, it may be confusing which constructor gets called here: auto d = DVECTOR2(1.5); That might be true. I just did what felt most convenient, but perhaps that is not always the solution. D2 has changed the meaning of inout to mean something like templatize just the mutable/const/immutable qualification of the parameter but it is not implemented fully yet. Look at Inout Functions on the Functions spec: Foolish of me to forget about inout functions. Is there any possibility though that the inout tag offers a solution to my initial problem, where the constructor couldn't be evaluted at compile time? It feels a bit redundant if you would have to have unique constructors just to enable support for immutable instantiations of your class, or perhaps this lies within the use of templates and their generic parameters? I've been at this problem for over a day and it feels awful to be left with no choice and move away from using templates and instead having walls of boilerplate code just to support immutable and const instantiations of one's structure.
Re: Dynamic multidimensional arrays
On 7/5/2011 2:00 AM, Jonathan M Davis wrote: On 2011-07-04 23:56, Jonathan M Davis wrote: On 2011-07-04 23:42, Bellum wrote: Can anyone point me in the right direction for doing something like this in D: char[][] anArray; int rows, cols; ... anArray = new char[rows][cols]; It isn't possible in this way because rows cannot be read at compile time, which seems to me to be the point of dynamic arrays. :P auto anArray = new char[][](rows, cols); Putting the numbers directly in the brackets tries to create a static array once you get beyond the first dimension. So, auto anArary = new char[4][5]; would create a dynamic array of length for with elements which are static arrays of length 5. If you want it to by dynamic all the way, you need to put the dimensions in the parens like above. Personally, I _never_ put them in the brackets, even when the dynamic array has just one dimension. It's just simpler to always put them in the parens and not worry about it. Correction, auto anArray = new char[4][5]; would create a dynamic array of length 5 of static arrays with length 4, though auto anArray = new char[][](4, 5); does create a dynamic array of length 4 of dynamic arrays of length 5. It quickly gets confusing when dealing with dimensions and static arrays IMHO. - Jonathan M Davis Wow, that is confusing. I think I'll stick to using parans, too; thanks for the tip!
Re: Dynamic multidimensional arrays
If you want it to by dynamic all the way, you need to put the dimensions in the parens like above. Personally, I _never_ put them in the brackets, even when the dynamic array has just one dimension. It's just simpler to always put them in the parens and not worry about it. Maybe we should force the parens approach even for one dimension. At least dmd should give better diagnostics. It's damn hard to even find that syntax in the docs.
Re: Dynamic multidimensional arrays
On 2011-07-05 11:29, Trass3r wrote: If you want it to by dynamic all the way, you need to put the dimensions in the parens like above. Personally, I _never_ put them in the brackets, even when the dynamic array has just one dimension. It's just simpler to always put them in the parens and not worry about it. Maybe we should force the parens approach even for one dimension. At least dmd should give better diagnostics. It's damn hard to even find that syntax in the docs. The problem is that there's nothing wrong with putting the dimensions in the brackets. It makes perfect sense _if you want dynamic arrays of static arrays_. However, that's not normally what people want. _Everyone_ who attempts to create a multidimensional dynamic array runs into this problem. Putting the dimension in the brackets for a single dimension dynamic array matches exactly what's going on when you put the dimensions in the brackets with multi-dimension arrays. So, disallowing it wouldn't really make sense. The issue is that it having multi-dimensional arrays where elements are static arrays makes perfect sense under certain circumstances, and it uses pretty much exactly the syntax that you'd expect it to if you were looking for that, but that that syntax is exactly what people try to use when using multi- dimensional arrays which are purely dynamic. So, this screws over everyone, but changing it risks removing a valid feature. So, I really don't know how it should be handled. I fear that it's like how int[5][4] a; int a[4][5]; produce the same array. It matches perfectly how the language works in general but is exactly the opposite of what programmers expect, since they don't think like a compiler. Changing it makes the language inconsistent, but keeping it as-is causes problems for everyone using the language. It sucks pretty much no matter what you do. Maybe someone can come up with a way to clean things up, but as it stands, static arrays tend to screw over programmers until they understand their quirks (generally after getting bitten by errors like the OP ran into). The one thing that _is_ clear, however, is that if the online docs are not clear about the paren syntax, then they should be updated. And they should probably explain the issue of dynamic arrays of static arrays more clearly so that those who read the docs will at least have some clue what is going on and avoid this issue. - Jonathan M Davis
Re: swap doesn't work in CTFE?
On 7/4/11 11:39 PM, Daniel Murphy wrote: bearophilebearophileh...@lycos.com wrote in message news:iut093$1bjg$1...@digitalmars.com... Daniel Murphy: Same thing happens with pointers. Reduced: Pointers to structs in CTFE will work in DMD 2.054 :-) When they don't crash the compiler, that is. http://d.puremagic.com/issues/show_bug.cgi?id=6250 Is there any point in implementing CTFE in the compiler when LLVM already allows you to define functions and JIT compile them? Why write yet another JIT compiler that in fact doesn't optimize anything and just interprets everything as it comes? I'm sure with LLVM you can do all of what DMD currently does and more.
Re: swap doesn't work in CTFE?
On 2011-07-05 12:10, Ary Manzana wrote: On 7/4/11 11:39 PM, Daniel Murphy wrote: bearophilebearophileh...@lycos.com wrote in message news:iut093$1bjg$1...@digitalmars.com... Daniel Murphy: Same thing happens with pointers. Reduced: Pointers to structs in CTFE will work in DMD 2.054 :-) When they don't crash the compiler, that is. http://d.puremagic.com/issues/show_bug.cgi?id=6250 Is there any point in implementing CTFE in the compiler when LLVM already allows you to define functions and JIT compile them? Why write yet another JIT compiler that in fact doesn't optimize anything and just interprets everything as it comes? I'm sure with LLVM you can do all of what DMD currently does and more. CTFE has a major impact on how programs are compiled. It wouldn't make any sense to try and take it out the compiler itself. Not only does it affect what you can initialize module and static variables to, but you can use it in conditional compilation and template instantiation. It's an integral part of the language itself and an integral part of the compilation process. Splitting it out wouldn't work. Not to mention, CTFE happens in the _frontend_ of the compiler, not the backend, and LLVM is the backend of LDC. dmd, gdc, and LDC all share the same frontend. So, unless the JIT compiler were in the frontend, it wouldn't matter on whit how good it is, because it couldn't be used in the frontend - which is where CTFE needs to happen. - Jonathan M Davis
Re: swap doesn't work in CTFE?
On 7/4/2011 10:39 PM, Daniel Murphy wrote: bearophilebearophileh...@lycos.com wrote in message news:iut093$1bjg$1...@digitalmars.com... Daniel Murphy: Same thing happens with pointers. Reduced: Pointers to structs in CTFE will work in DMD 2.054 :-) When they don't crash the compiler, that is. http://d.puremagic.com/issues/show_bug.cgi?id=6250 Perfect! Thank you. I verified the exception is a stack overflow for the ref case as well (but since you know the compiler internals I'm sure you knew that already ;) ).
Hashing protocol
Since some time the built-in associative arrays don't use search trees to manage collisions, but just linked lists. So if you want to implement the hash protocol for a struct do you need to add it a opCmp() too still (that was needed just for those trees), or is now opEquals() enough (plus toHash)? If the answer is positive then the part about hashing of this page is obsolete: http://www.digitalmars.com/d/2.0/hash-map.html Bye, bearophile
Postblit not called in one case
With DMD 2.053 the second assert of this program fires, is this a DMD bug or it's me that's missing something? struct Foo { int[] data; this(int n) { data.length = n; } this(this) { data = data.dup; } } void main() { Foo f1, f2; f1 = Foo(1); f2 = f1; assert(f1.data.ptr != f2.data.ptr); // OK f1 = f2 = Foo(1); assert(f1.data.ptr != f2.data.ptr); // asserts } Bye and thank you, bearophile