digitalmars.D.learn - comparing pointers passed to and returned from funcs
- spir <denis.spir gmail.com> Mar 01 2011
- bearophile <bearophileHUGS lycos.com> Mar 01 2011
- bearophile <bearophileHUGS lycos.com> Mar 01 2011
- bearophile <bearophileHUGS lycos.com> Mar 01 2011
- Bekenn <leaveme alone.com> Mar 01 2011
- bearophile <bearophileHUGS lycos.com> Mar 01 2011
- Bekenn <leaveme alone.com> Mar 01 2011
- bearophile <bearophileHUGS lycos.com> Mar 01 2011
- Bekenn <leaveme alone.com> Mar 01 2011
- Bekenn <leaveme alone.com> Mar 01 2011
- spir <denis.spir gmail.com> Mar 02 2011
- "Steven Schveighoffer" <schveiguy yahoo.com> Mar 02 2011
Hello,
It seems to be the kind of stupid issue that will make you laugh about me. But
I cannot grasp and want to move forward anyway; so, let us be bold and take the
risk ;-)
I'm modeling a little dynamic language. Elements (values, objects) are pointers
to structs (actually tagged unions) allocated on the heap. I have a problem in
passing and returning those pointers to and from primitive procedures.
Precisely, unlike in D, Logical (boolean) operations only accept Logical
elements true/false (called TRUE/FALSE on implementation side for obvious
reason):
enum TRUE = new DElement(true);
enum FALSE = new DElement(false);
So, I thought I could write those operations by comparing pointers directly,
eg:
Element not (Element operand) {
// checks type
operand.checkLogical()
return (operand == TRUE) ? FALSE : TRUE;
}
...
assert ( not(TRUE) == FALSE );
This fails! It even fails "doubly"...
When I call not(TRUE), TRUE (the pointer) inside the func is not equal to the
global constant. Thus, not always returns FALSE. And in fact this is also
wrong, because I have the same problem on the return value as well: the FALSE
returned is not equal to the global FALSE.
But the pointed structs are ok. Each one holds a D boolean of the correct value
(a member called 'logical'). Thus, the following succeeds:
Element not (Element operand) {
// checks type & returns the 'logical' member
auto log = operand.checkLogical();
return (log) ? FALSE : TRUE;
}
...
assert ( not(TRUE).logical == false );
Here, I operate on the structs instead of on the pointers, both to perform the
operation and in the assert. What I understand is: all happens like if D would
copy the pointed structs on parameter passing and on return. I thought D would
only copy the pointers (in both directions), which would let me compare said
pointers directly.
What do I miss?
It is not a serious problem since the workaround is easy and not very costly.
But I wish to understand why I cannot operate on constant 'identity'. As said
above, this must a trivial issue I simply cannot guess...
Thank you,
Denis
--
_________________
vita es estrany
spir.wikidot.com
Mar 01 2011
spir:It seems to be the kind of stupid issue that will make you laugh about me. But I cannot grasp and want to move forward anyway; so, let us be bold and take the risk ;-)
Be bold. Understanding things is much more important. I've being wrong hundreds of times on D newsgroups, but I'm getting better.This fails! It even fails "doubly"...
Reduced program (and Walter thinks that avoiding printf-related bugs is not important. He's wrong. I use printf often enough in D): import core.stdc.stdio: printf; struct Foo { bool b; this(bool b_) { this.b = b_; } } enum Foo* TRUE = new Foo(true); enum Foo* FALSE = new Foo(false); Foo* not(Foo* op) { return (op == TRUE) ? FALSE : TRUE; } void main() { //assert(not(TRUE) == FALSE); printf("%x\n", TRUE); printf("%x\n", FALSE); printf("%x\n", not(TRUE)); printf("%x\n", not(not(TRUE))); }Here, I operate on the structs instead of on the pointers, both to perform the operation and in the assert. What I understand is: all happens like if D would copy the pointed structs on parameter passing and on return. I thought D would only copy the pointers (in both directions), which would let me compare said pointers directly. What do I miss?
DMD is not copying the structs, just pointers. I think it's happening something like with enum associative arrays. Pointers are run-time things. You are asking for a new at compile-time. This is the asm produced by that program (-O -release): _D4test3Foo6__ctorMFNcbZS4test3Foo comdat push EAX mov CL,8[ESP] mov [EAX],CL pop ECX ret 4 _D4test3notFPS4test3FooZPS4test3Foo comdat L0: push EAX mov ECX,offset FLAT:_D20TypeInfo_PS4test3Foo6__initZ push EAX push EBX push 1 push ECX call near ptr __d_newarrayT add ESP,8 mov EAX,EDX push 1 call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo cmp EAX,8[ESP] jne L3D mov EDX,offset FLAT:_D20TypeInfo_PS4test3Foo6__initZ push 1 push EDX call near ptr __d_newarrayT add ESP,8 mov EAX,EDX push 0 call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo jmp short L56 L3D: mov EBX,offset FLAT:_D20TypeInfo_PS4test3Foo6__initZ push 1 push EBX call near ptr __d_newarrayT add ESP,8 mov EAX,EDX push 1 call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo L56: pop EBX add ESP,8 ret __Dmain comdat L0: push EAX mov EAX,offset FLAT:_D20TypeInfo_PS4test3Foo6__initZ push EBX push ESI push 1 push 1 push EAX call near ptr __d_newarrayT add ESP,8 mov EAX,EDX call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo mov ECX,offset FLAT:_DATA push EAX push ECX call near ptr _printf mov EDX,offset FLAT:_D20TypeInfo_PS4test3Foo6__initZ push 0 push 1 push EDX call near ptr __d_newarrayT add ESP,8 mov EAX,EDX call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo mov EBX,offset FLAT:_DATA push EAX push EBX call near ptr _printf mov ESI,offset FLAT:_D20TypeInfo_PS4test3Foo6__initZ push 1 push 1 push ESI call near ptr __d_newarrayT add ESP,8 mov EAX,EDX call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo call near ptr _D4test3notFPS4test3FooZPS4test3Foo push EAX push EBX call near ptr _printf push 1 push 1 push ESI call near ptr __d_newarrayT add ESP,8 mov EAX,EDX call near ptr _D4test3Foo6__ctorMFNcbZS4test3Foo call near ptr _D4test3notFPS4test3FooZPS4test3Foo call near ptr _D4test3notFPS4test3FooZPS4test3Foo push EAX push EBX call near ptr _printf add ESP,020h xor EAX,EAX pop ESI pop EBX pop ECX ret My suspect is confirmed, DMD is acting as with enum associative arrays. This is a compiler bug. DMD has to act correctly and not create a struct every time, or it has to give a compile-time error. Not this mess. Bye, bearophile
Mar 01 2011
This seems to work:
import core.stdc.stdio: printf;
struct Foo {
bool b;
this(bool b_) { this.b = b_; }
}
const(Foo)* TRUE, FALSE;
static this() {
TRUE = new const(Foo)(true);
FALSE = new const(Foo)(false);
}
const(Foo)* not(const(Foo)* op) {
return (op == TRUE) ? FALSE : TRUE;
}
void main() {
assert(not(TRUE) == FALSE);
printf("%x\n", TRUE);
printf("%x\n", FALSE);
printf("%x\n", not(TRUE));
printf("%x\n", not(not(TRUE)));
}
Bye,
bearophile
Mar 01 2011
On 3/1/11 3:00 PM, bearophile wrote:const(Foo)* TRUE, FALSE;
I'd remove those parens; you don't want people modifying TRUE or FALSE.
Mar 01 2011
Bekenn:I'd remove those parens; you don't want people modifying TRUE or FALSE.
Please, show me working code that implements your idea :-) Bye, bearophile
Mar 01 2011
On 3/1/11 4:12 PM, bearophile wrote:Bekenn:I'd remove those parens; you don't want people modifying TRUE or FALSE.
Please, show me working code that implements your idea :-)
Touche. I'll have to test that out once I get back from work...
Mar 01 2011
Bekenn:Touche. I'll have to test that out once I get back from work...
Sorry for that answer of mine, we are here to learn and cooperate, not to fight :-) It's just I sometimes have problems with const things in D, and sometimes DMD has problems with const things. Bye, bearophile
Mar 01 2011
On 3/1/11 5:31 PM, bearophile wrote:Bekenn:Touche. I'll have to test that out once I get back from work...
Sorry for that answer of mine, we are here to learn and cooperate, not to fight :-) It's just I sometimes have problems with const things in D, and sometimes DMD has problems with const things.
Hey, no problem; I thought it was funny...
Mar 01 2011
On 3/1/2011 4:12 PM, bearophile wrote:Bekenn:I'd remove those parens; you don't want people modifying TRUE or FALSE.
Please, show me working code that implements your idea :-) Bye, bearophile
Here you go; I only changed the one line. Compiles and works just fine in dmd 2.051. const Foo* TRUE, FALSE; instead of const(Foo)* TRUE, FALSE;
Mar 01 2011
On 03/02/2011 02:24 PM, Steven Schveighoffer wrote:On Tue, 01 Mar 2011 18:11:00 -0500, bearophile <bearophileHUGS lycos.com> wrote:http://d.puremagic.com/issues/show_bug.cgi?id=5678
I think there is a general bug where any time the compiler uses an enum, it simply replaces the expression declared for the enum. So basically enum TRUE = new DElement(true); void main() { auto delem1 = TRUE; auto delem2 = TRUE; assert(delem1 is delem2); // fails } gets morphed into this: void main() { auto delem1 = new Delement(true); auto delem2 = new Delement(true); assert(delem1 is delem2); // fails } Obviously this works great when the enum is a value type or a string literal (which is created at compile time). However, it is not so great for things like AAs, array literals, objects, or structs. I think there are a few of these bugs in bugzilla, and there should be at least a tracker, and if not, they should all be combined. This is a serious problem in D, and really creates havoc (both performance-wise and semantically). I don't anticipate there is an easy fix. Essentially, I'd say enum is completely useless except for builtin types and strings.
Thank you Steven & Bearophile. This solves my problem. I first did not get Bearophile's answer about run/compile-time constants (I mean enums). I thought the time when they are created is irrelevant, isn't it? Anyway, placing the constant defs inside a module's <static this () {...}> block does what I mean. It does, in fact, ensure *unicity*. But I don't really understand the relation with Steven's explanation above: why/how does the fact that a constant's def is inside static this() prevent the compiler to rewrite it like shown above? Also, I basically don't understand why dmd does that anyway: it's obviously un-ecological ;-) Denis -- _________________ vita es estrany spir.wikidot.com
Mar 02 2011
On Tue, 01 Mar 2011 18:11:00 -0500, bearophile <bearophileHUGS lycos.com> wrote:http://d.puremagic.com/issues/show_bug.cgi?id=5678
I think there is a general bug where any time the compiler uses an enum, it simply replaces the expression declared for the enum. So basically enum TRUE = new DElement(true); void main() { auto delem1 = TRUE; auto delem2 = TRUE; assert(delem1 is delem2); // fails } gets morphed into this: void main() { auto delem1 = new Delement(true); auto delem2 = new Delement(true); assert(delem1 is delem2); // fails } Obviously this works great when the enum is a value type or a string literal (which is created at compile time). However, it is not so great for things like AAs, array literals, objects, or structs. I think there are a few of these bugs in bugzilla, and there should be at least a tracker, and if not, they should all be combined. This is a serious problem in D, and really creates havoc (both performance-wise and semantically). I don't anticipate there is an easy fix. Essentially, I'd say enum is completely useless except for builtin types and strings. -Steve
Mar 02 2011









bearophile <bearophileHUGS lycos.com> 