Dynamic multidimensional arrays

2011-07-05 Thread Bellum
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

2011-07-05 Thread Jacob Carlborg

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

2011-07-05 Thread Jonathan M Davis
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

2011-07-05 Thread Jonathan M Davis
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

2011-07-05 Thread bearophile
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

2011-07-05 Thread simendsjo

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

2011-07-05 Thread Steven Schveighoffer
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

2011-07-05 Thread Loopback

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

2011-07-05 Thread Ali Çehreli
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

2011-07-05 Thread Loopback

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

2011-07-05 Thread Bellum

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

2011-07-05 Thread Trass3r

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

2011-07-05 Thread Jonathan M Davis
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?

2011-07-05 Thread Ary Manzana

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?

2011-07-05 Thread Jonathan M Davis
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?

2011-07-05 Thread Johann MacDonagh

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

2011-07-05 Thread bearophile
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

2011-07-05 Thread bearophile
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