Re: Segfault with std.container.Array but not regular dynamic array
On Wednesday, 28 November 2012 at 22:13:05 UTC, Dan wrote: On Wednesday, 28 November 2012 at 20:30:41 UTC, Maxim Fomin wrote: On Wednesday, 28 November 2012 at 18:08:59 UTC, Dan wrote: This code with version=bug produces garbage because of opAssign. It seems that opAssign is actually called before accessing map: Maxim, thanks for looking more at this. This bug is not affecting my work in any way - I'm just trying to learn more about D and how to debug, and your responses are helpful. I've now built druntime and phobos with debug to see if I can see what is going on more. For me the relevant assembly of your code looks like below. I see the value in the assoc array get created and memset initialized to 0 inside aaA.d function _aaGetX with this line: memset(ptail + aligntsize(keytitsize), 0, valuesize); // zero value Then between +62 and +102 it goes off the rails and upon entry to opAssign *this* is likely garbage. I can't be certain because the values I see are 0, which would be consistent with 0 initialization - but could also just be luck. At this point I wish I knew some assembly. Anyway, I don't know if it is a problem with associative array code, per se, or the code generated by the compiler when opAssign and/or postblit are defined for the value type. I do know that if you have no postblit and no opAssign there are no issues - even with a destructor. This is consistent with the examples you have shown, they have postblit and/or opAssign as well as the RefCount code which has postblit and dtor. In both your example crash and the RefCount crash the actual seg fault is in the dtor accessing bogus data because as you pointed out it was not correctly initialized. Thanks Dan skipped This doesn't look like assembly for previous source. Please provide the source for which you have assembly and tell which dmd options do you use.
Re: assertion failure with template instantiation of forward reference class
On Thursday, 29 November 2012 at 01:38:50 UTC, bearophile wrote: comco: Looks like a bug? This is what DMD 2.061alpha prints, it doesn't crash: ...\dmd2\src\phobos\std\range.d(603): Error: static assert Cannot put a string into a LockingTextWriter ...\dmd2\src\phobos\std\format.d(2349):instantiated from here: put!(LockingTextWriter, string) ...\dmd2\src\phobos\std\format.d(2782):instantiated from here: formatValue!(LockingTextWriter, TypeInfo_Class, char) ...\dmd2\src\phobos\std\format.d(415):instantiated from here: formatGeneric!(LockingTextWriter, TypeInfo_Class, char) ...\dmd2\src\phobos\std\stdio.d(712):... (1 instantiations, -v to show) ... ...\dmd2\src\phobos\std\stdio.d(1618):instantiated from here: write!(TypeInfo_Class,char) test.d(5):instantiated from here: writeln!(TypeInfo_Class) Bye, bearophile Nice. Thanks!
Re: Is there a portable way to limit memory/cpu usage of a D application?
On Thursday, 29 November 2012 at 04:44:34 UTC, Mike Young wrote: On Wednesday, 9 November 2011 at 17:13:14 UTC, Dejan Lekic wrote: Sure nothing prevents me from using setrlimit() in my D app, but perhaps it is something to think about a portable way of doing that. I know I'm over a year late coming in on this conversation, but how would you use setrlimit() in your D app at all? I can't seem to figure out what the correct library is to include in my program to be able to call set/getrlimit in any manner. Thanks! Well, if it is not in the posix module, then you simply use it by declaring extern(C) int setrlimit(int resource, const void* rlim); or something similar if you define the rlimit struct somewhere. Remember, you can call C functions from your D code anytime, anywhere.
static assert
Another funny thing. import std.conv; static assert(0, 1 != ~ text(2)); outputs Error: static assert ['1',' ','!','=',' ','2']
Re: static assert
Jack Applegame: import std.conv; static assert(0, 1 != ~ text(2)); outputs Error: static assert ['1',' ','!','=',' ','2'] This is known problem, it's already in Bugzilla, and maybe there's already a patch for it (there are about one hundred patches waiting in Bugzilla). Bye, bearophile
Re: Segfault with std.container.Array but not regular dynamic array
On Thursday, 29 November 2012 at 07:59:02 UTC, Maxim Fomin wrote: This doesn't look like assembly for previous source. Please provide the source for which you have assembly and tell which dmd options do you use. Well, I'm using the latest dmd (from the trunk), phobos, druntime, so I could build and step through. rdmd -version=bug --force --build-only -g -w -property -I/home/dbdavidson/stage/vibe.d/source -I/home/dbdavidson/plusauri/dlang -L-levent_pthreads -L-levent -L-lssl -L-lcrypto /home/dbdavidson/tmp/again.d dmd -v DMD v2.061 DEBUG DMD64 D Compiler v2.061 --- import core.stdc.stdio : printf; struct S { long x = 42; version(bug) { void opAssign(S rhs) { printf(Assign %d\n, this.x); } } } //alias RefCounted!(int) Foo; alias S Foo; Foo[int] map; void main() { map[3] = Foo(); printf(%d\n, map[3].x); } (gdb) disass Dump of assembler code for function _Dmain: 0x0041a630 +0: push %rbp 0x0041a631 +1: mov%rsp,%rbp 0x0041a634 +4: sub$0x38,%rsp 0x0041a638 +8: push %rbx = 0x0041a639 +9:mov$0x3,%eax 0x0041a63e +14: mov%eax,-0x30(%rbp) 0x0041a641 +17: lea-0x30(%rbp),%rcx 0x0041a645 +21: movabs $0x8,%rdx 0x0041a64f +31: movabs $0x43cc10,%rsi 0x0041a659 +41: mov%fs:0x0,%rdi 0x0041a662 +50: add0x229957(%rip),%rdi# 0x643fc0 0x0041a669 +57: callq 0x41ae84 _aaGetX 0x0041a66e +62: mov%rax,-0x28(%rbp) 0x0041a672 +66: test %rax,%rax 0x0041a675 +69: jne0x41a681 _Dmain+81 0x0041a677 +71: mov$0x12,%edi 0x0041a67c +76: callq 0x41a710 _D5again7__arrayZ 0x0041a681 +81: movabs $0x2a,%rax 0x0041a68b +91: mov%rax,-0x18(%rbp) 0x0041a68f +95: mov%rax,%rsi 0x0041a692 +98: lea-0x20(%rbp),%rdi 0x0041a696 +102: callq 0x41a5c8 _D5again1S8opAssignMFS5again1SZv 0x0041a69b +107: mov-0x20(%rbp),%rcx 0x0041a69f +111: mov-0x28(%rbp),%rdx 0x0041a6a3 +115: mov%rcx,(%rdx)
canFind typing
I have used std.algorithm.canFind with different tuple types by mistake, and the compiler has not complained. So to show it I have written some reduced code that uses just numbers: import std.algorithm: canFind; void main() { int[] arr1 = [1, 2]; double x1 = 2.0; assert(arr1.canFind(x1)); double[] arr2 = [1.0, 2.0]; int x2 = 2; assert(arr2.canFind(x2)); } Are both of those canFind calls acceptable? Bye, bearophile
Re: telnet and D
vibe.d is very modular, just import what you need. I hate to push it, but it has very good documentation and examples. Its designed for web apps, but it makes a nice little web library as well. import vibe.vibe; void main() { auto client = new HttpClient; client.connect(www.google.com, 80); auto res = client.request((req){ req.url = /; }); logInfo(Response: %d, res.statusCode); foreach( k, v; res.headers ) logInfo(Header: %s: %s, k, v); (new NullOutputStream).write(res.bodyReader); client.disconnect(); } That does indeed look clean. Now I'm using a ubyte[1] buffer to try and read single bytes from my sockets. their tcp example looks pretty clean: import vibe.d; static this() { auto conn = connectTcp(time-b.timefreq.bldrdoc.gov, 13); logInfo(The time is: %s, cast(string)conn.readAll()); } let's see how it'll hold up when I try to deal with raw bytes :)
Re: Segfault with std.container.Array but not regular dynamic array
On Thursday, 29 November 2012 at 12:38:03 UTC, Dan wrote: On Thursday, 29 November 2012 at 07:59:02 UTC, Maxim Fomin wrote: This doesn't look like assembly for previous source. Please provide the source for which you have assembly and tell which dmd options do you use. Well, I'm using the latest dmd (from the trunk), phobos, druntime, so I could build and step through. This is version generated by rdmd -version=bug --force --build-only -g -w -property. The only difference between this and yours is in +71. +00:push %rbp +01:mov%rsp,%rbp +04:sub$0x38,%rsp +08:push %rbx // push 3 as a pkey, -0x30(%rbp) is 3 +09:mov$0x3,%eax +14:mov%eax,-0x30(%rbp) +17:lea-0x30(%rbp),%rcx // push valuesize +21:movabs $0x8,%rdx // push keyti +31:movabs $0x430f50,%rsi // push map address, it is tls object +41:mov%fs:0x0,%rdi +50:add0x21e22f(%rip),%rdi# 0x636fb0 // call, keyti=8, aa=map, valuesize=8, pkey=3 +57:callq 0x419140 _aaGetX // store return value in -0x28(%rbp) +62:mov%rax,-0x28(%rbp) // check array bounds +66:test %rax,%rax +69:jne0x418d99 _Dmain+81 +71:mov$0x13,%edi +76:callq 0x418e28 _D4main7__arrayZ // constructing S rhs for opAssign +81:movabs $0x2a,%rax +91:mov%rax,-0x18(%rbp) // rhs +95:mov%rax,%rsi // making this from -0x20(%rbp), but it was stored in -0x28(%rbp) +98:lea-0x20(%rbp),%rdi // opAssign loads this from %rdi +102: callq 0x418ce0 _D4main1S8opAssignMFS4main1SZv // replace content in -0x28(%rbp) by -0x20(%rbp) +107: mov-0x20(%rbp),%rcx +111: mov-0x28(%rbp),%rdx +115: mov%rcx,(%rdx) // load previously created object +118: movl $0x3,-0x10(%rbp) +125: lea-0x10(%rbp),%rcx +129: movabs $0x8,%rdx +139: movabs $0x430f50,%rsi +149: mov%fs:0x0,%rax +158: mov0x21e1c3(%rip),%rbx# 0x636fb0 +165: mov(%rax,%rbx,1),%rdi +169: callq 0x4192b8 _aaGetRvalueX // store pointer to existed object +174: mov%rax,-0x8(%rbp) // check array bounds +178: test %rax,%rax +181: jne0x418e09 _Dmain+193 +183: mov$0x14,%edi +188: callq 0x418e28 _D4main7__arrayZ // load x member +193: mov-0x8(%rbp),%rcx +197: mov(%rcx),%rsi +200: movabs $0x430ac0,%rdi +210: xor%eax,%eax +212: callq 0x4188e0 printf@plt +217: xor%eax,%eax +219: pop%rbx +220: leaveq +221: retq End of assembler dump. Main stack frame looks follows: -0x30(%rbp):-0x28(%rbp) 3 as a pkey arg to _aaGetX -0x28(%rbp):-0x20(%rbp) pointer to S allocated by _aaGetX -0x20(%rbp):-0x18(%rbp) uninitialized struct - this ptr -0x18(%rbp):-0x10(%rbp) constructed struct passed as rhs to opAssign -0x10(%rbp):-0x08(%rbp) 3 as a pkey arg to _aaGetRvalueX -0x08(%rbp):-0x00(%rbp) pointer to S returned from _aaGetRvalueX It seems that dmd allocates space for two structs, one non-initialized, second initialized, issues call to druntime, then places a call to opAssign with non-initialized as this object with initialized as rhs argument, then writes content on non-initialized to allocated by druntime. So, this looks like a codegen bug. By the way, if the code is compiled with command dmd main -g -release -noboundscheck -version=bug, opAssign call is placed before calling _aaGetX.
Re: Calls to struct methods and immutable
On 11/27/2012 05:31 PM, Dan wrote: I'm using a custom gdup that recursively copies fields and requires no support from nested structs. If a dup is provided by a struct it will be called. No guarantees, but have a look. https://github.com/patefacio/d-help/blob/master/d-help/opmix/mix.d Thanks for that -- I'll look through it carefully. My one caveat here is that in general I'm reluctant to rely too strongly on 3rd-party libraries at this stage of D's development. That's particularly true where stuff like this is concerned -- which might well be best placed in the standard library itself. Generic, broadly-applicable .dup and .idup commands would seem to be something that should be available in Phobos ... ... anyway, back to the specifics -- even though I could use opmix, I'd still really like to understand for myself how to solve the problems described in my previous emails -- in particular, how to effectively idup my struct containing the Node[uint] associative array _without_ relying on some external library. My feeling is I'll learn more about D this way ... :-)
Can operators return type?
Hi! It would useful for some my project,if operators could be a template,that return type.Something like alias TypeTuple!(int,char) types; static assert(types[1] == char) //opIndex So can I define something like that?
Re: opSlice Bug?
On 11/29/2012 08:15 AM, Namespace wrote: Why I have to write arr2[] += arr[][] instead of arr2[] += arr[] ? Bug or 'feature'? :P Code: http://dpaste.dzfl.pl/4c732f4c opSplice, eh? Is that another undocumented feature or one that has been deprecated? Ali
Re: opSlice Bug?
On Thursday, 29 November 2012 at 16:46:45 UTC, Ali Çehreli wrote: On 11/29/2012 08:15 AM, Namespace wrote: Why I have to write arr2[] += arr[][] instead of arr2[] += arr[] ? Bug or 'feature'? :P Code: http://dpaste.dzfl.pl/4c732f4c opSplice, eh? Is that another undocumented feature or one that has been deprecated? Ali http://dlang.org/operatoroverloading.html#Slice
Re: Can operators return type?
Zhenya: It would useful for some my project,if operators could be a template,that return type. D operators are functions, and D functions return values. And in D types are not values (unlike Python and several other languages), unless you use a Typeinfo or something. Maybe if you explain better what you are trying to do someone will be able to suggest you an alternative solution. D is not as flexible as Lisp, but it doesn't lack meta-programming/type-processing capabilities. Bye, bearophile
Re: opSlice Bug?
Ali Çehreli: opSplice, eh? Is that another undocumented feature or one that has been deprecated? I think it's not deprecated: http://dlang.org/operatoroverloading.html#Slice Bye, bearophile
Re: Can operators return type?
On 2012-11-29, 17:33, Zhenya wrote: Hi! It would useful for some my project,if operators could be a template,that return type.Something like alias TypeTuple!(int,char) types; static assert(types[1] == char) //opIndex So can I define something like that? This works out of the box. If you want to define your own TypeTuple-like construct, the answer is most likely going to be no. -- Simen
Re: opSlice Bug?
On 11/29/2012 08:50 AM, Namespace wrote: On Thursday, 29 November 2012 at 16:46:45 UTC, Ali Çehreli wrote: On 11/29/2012 08:15 AM, Namespace wrote: Why I have to write arr2[] += arr[][] instead of arr2[] += arr[] ? Bug or 'feature'? :P Code: http://dpaste.dzfl.pl/4c732f4c opSplice, eh? Is that another undocumented feature or one that has been deprecated? Ali http://dlang.org/operatoroverloading.html#Slice Thanks. I really did read it as opS_p_lice, found a few references on dlang.org, none on any spec page and got a little frustrated. I did not realize that I had clearly misread it. I had even written some notes about opSlice: http://ddili.org/ders/d.en/operator_overloading.html Apparently I had thought that it better returned a special type: struct Range { // ... } struct Container { // For the object[] syntax Range opSlice() { Range allElements; // ... must provide access to all elements ... return allElements; } /* ... */ } Ali
Re: opSlice Bug?
Yes, that could be better (but I don't like it), but my code should compile as well, or not?
Re: opSlice Bug?
On 11/29/2012 08:15 AM, Namespace wrote: Why I have to write arr2[] += arr[][] instead of arr2[] += arr[] ? Bug or 'feature'? :P Code: http://dpaste.dzfl.pl/4c732f4c Apparently, the array-wise operations require the following syntax: a[] += b[]; In other words, the compiler wants to see [] on the right-hand side as well. The following does not work with the same error message that you get: int[] a, b; a[] += b; Error: invalid array operation a[] += b (did you forget a [] ?) It is the same in your case. You have a function that returns a slice but the compiler still wants to see [] on the rigth-hand side: int[] foo() { int[] b; return b; } void main() { int[] a; a[] += foo();// -- Same compilation error } That's why you need to put the [] after it: a[] += foo()[]; I think it is just the requirement of the syntax. (?) Ali
Re: opSlice Bug?
That is what I thought also. That is awfully and limited. :/
Initializing values in associative arrays
How safe is it to rely on doing something like this: uint[size_t] x; foreach(i; iota(0, 10)) x[i]++; foreach(i; iota(5, 15)) x[i]++; ... ? In this case correct output comes out -- that is, values for keys 1-4 and 10-14 come out as 1, values for keys 5-9 come out as 2 -- but it seems a bit shaky to assume that just incrementing x[i] without first checking ((i in x) !is null) will come out correctly. I note that the above works even if uint[size_t] is changed to real[size_t], which is a surprise, because I'd have assumed that everything would come out as nan's.
Re: canFind typing
Jonathan M Davis: Why wouldn't they be? You can compare int and double, and that's what find and canFind care about. Right, it's a matter of equality operator. In my code I was performing canFind on an array of tuples. So I didn't realize that the following code (where both tuple field type and field name are different) is accepted in D (probably I am getting used to the higher type strictness of functional languages): import std.typecons: Tuple; alias T1 = Tuple!(int, x); alias T2 = Tuple!(double, y); void main(string[] args) { assert(T1(1) == T2(1)); } Bye, bearophile
Re: Initializing values in associative arrays
Joseph Rushton Wakeling: How safe is it to rely on doing something like this: uint[size_t] x; foreach(i; iota(0, 10)) x[i]++; foreach(i; iota(5, 15)) x[i]++; This is part of the D associative array specs, so in theory it's safe, but you have to keep this implementation bug in account: http://d.puremagic.com/issues/show_bug.cgi?id=3825 I note that the above works even if uint[size_t] is changed to real[size_t], which is a surprise, because I'd have assumed that everything would come out as nan's. This is a known AA bug :-( I think that there is not yet a patch to fix it. Bye, bearophile
Re: Apparent problem with GC not collecting on Windows
Because you used uint instead of ubyte, array is bigger, memory exhausts faster. Oh, I see. 3. Why it helps? GC.free(data.ptr); Initial leak happened because for some reason array allocated in previous iteration was not collected by GC when allocating new one, so the new one was allocated in another space growing the heap. If you place GC.free the array gets removed from heap on each iteration and each new allocation reuses the same memory, heap doesn't grow. If we do this manually it's works, but automatically is broken?
Re: Calls to struct methods and immutable
On Thursday, 29 November 2012 at 16:28:42 UTC, Joseph Rushton Wakeling wrote: My one caveat here is that in general I'm reluctant to rely too strongly on 3rd-party libraries at this stage of D's development. That's particularly true where stuff like this is concerned -- which might well be best placed in the standard library itself. Generic, broadly-applicable .dup and .idup commands would seem to be something that should be available in Phobos ... ... anyway, back to the specifics -- even though I could use opmix, I'd still really like to understand for myself how to solve the problems described in my previous emails -- in particular, how to effectively idup my struct containing the Node[uint] associative array _without_ relying on some external library. My feeling is I'll learn more about D this way ... :-) I feel the same way - as I said there are no guarantees, I'm using it but it may not cover the majority of cases and it may be obviated by whatever solution Walter is cooking up for copy construction and copying of const reference types. Doing it yourself is the best way to learn. What I really like about D is that you can have what seems like a crippling issue (no way to copy const objects) and use features like mixin compile time recursion to have a potentially nice general solution. I also think the dup should be formalized, maybe not as a keyword but a strong convention supported by the language, maybe phobos. For example, in your code you have already written 2 idup functions. The code below works as well with no need to write those custom functions. Besides, it should be safer (assuming it works ;-) because you can add new fields and have less to update. BTW: if you are still working on this be aware you may eventually have some (unwanted?) data sharing going on since there are no postblits and you have reference types with aliasing. Some descriptions of the code and its intentions are: https://github.com/patefacio/d-help/blob/master/doc/canonical.pdf Thanks Dan import std.stdio; import std.typecons; import std.conv; import std.exception; import opmix.mix; alias Tuple!(uint, id) Link; struct Node { uint id; Link[] links; void addLink(uint l) { links ~= Link(l); } } struct Network { Node[uint] nodes; void add(uint i, uint j) { if((i in nodes) is null) nodes[i] = Node(i); if((j in nodes) is null) nodes[j] = Node(j); nodes[i].addLink(j); nodes[j].addLink(i); } void print() { foreach(k; nodes.keys) { write([, k, ]); foreach(l; nodes[k].links) write( , l.id); writeln(); } writeln(); } } unittest { auto n1 = Node(1); n1.addLink(5); n1.addLink(6); writeln(n1.links); immutable n2 = cast(immutable)n1.gdup; writeln(n2.links); Network net1; net1.add(1,2); immutable Network net2 = cast(immutable)net1.gdup; writeln(net1); writeln(net2); }
Re: Apparent problem with GC not collecting on Windows
On 11/29/2012 12:06 PM, Michael wrote: Because you used uint instead of ubyte, array is bigger, memory exhausts faster. Oh, I see. 3. Why it helps? GC.free(data.ptr); Initial leak happened because for some reason array allocated in previous iteration was not collected by GC when allocating new one, so the new one was allocated in another space growing the heap. If you place GC.free the array gets removed from heap on each iteration and each new allocation reuses the same memory, heap doesn't grow. If we do this manually it's works, but automatically is broken? Nothing is broken. GC.free would have been applied by the GC only if there have been no more references to the allocated block of memory. The fact is, dmd uses a conservative GC. The issue is due to the combination of conservative GC, 32-bit address space, and a large chunk of memory. When that happens, it is very likely that any other value in the system, including an innocent int, has the risk of looking like a reference into that memory. For that reason the GC keeps that memory block allocated. The risk of that happening is grossly reduced in a 64-bit address space. Similarly, allocating a much smaller buffer helps as well. Alternatively, we can use a better GC or a runtime that has a better GC. Ali
Re: Segfault with std.container.Array but not regular dynamic array
On Thursday, 29 November 2012 at 15:06:07 UTC, Maxim Fomin wrote: On Thursday, 29 November 2012 at 12:38:03 UTC, Dan wrote: On Thursday, 29 November 2012 at 07:59:02 UTC, Maxim Fomin wrote: This doesn't look like assembly for previous source. Please provide the source for which you have assembly and tell which dmd options do you use. Well, I'm using the latest dmd (from the trunk), phobos, druntime, so I could build and step through. This is version generated by rdmd -version=bug --force --build-only -g -w -property. The only difference between this and yours is in +71. +00:push %rbp +01:mov%rsp,%rbp +04:sub$0x38,%rsp +08:push %rbx // push 3 as a pkey, -0x30(%rbp) is 3 +09:mov$0x3,%eax +14:mov%eax,-0x30(%rbp) +17:lea-0x30(%rbp),%rcx // push valuesize +21:movabs $0x8,%rdx // push keyti +31:movabs $0x430f50,%rsi // push map address, it is tls object +41:mov%fs:0x0,%rdi +50:add0x21e22f(%rip),%rdi# 0x636fb0 // call, keyti=8, aa=map, valuesize=8, pkey=3 +57:callq 0x419140 _aaGetX // store return value in -0x28(%rbp) +62:mov%rax,-0x28(%rbp) // check array bounds +66:test %rax,%rax +69:jne0x418d99 _Dmain+81 +71:mov$0x13,%edi +76:callq 0x418e28 _D4main7__arrayZ // constructing S rhs for opAssign +81:movabs $0x2a,%rax +91:mov%rax,-0x18(%rbp) // rhs +95:mov%rax,%rsi // making this from -0x20(%rbp), but it was stored in -0x28(%rbp) +98:lea-0x20(%rbp),%rdi // opAssign loads this from %rdi +102: callq 0x418ce0 _D4main1S8opAssignMFS4main1SZv // replace content in -0x28(%rbp) by -0x20(%rbp) +107: mov-0x20(%rbp),%rcx +111: mov-0x28(%rbp),%rdx +115: mov%rcx,(%rdx) // load previously created object +118: movl $0x3,-0x10(%rbp) +125: lea-0x10(%rbp),%rcx +129: movabs $0x8,%rdx +139: movabs $0x430f50,%rsi +149: mov%fs:0x0,%rax +158: mov0x21e1c3(%rip),%rbx# 0x636fb0 +165: mov(%rax,%rbx,1),%rdi +169: callq 0x4192b8 _aaGetRvalueX // store pointer to existed object +174: mov%rax,-0x8(%rbp) // check array bounds +178: test %rax,%rax +181: jne0x418e09 _Dmain+193 +183: mov$0x14,%edi +188: callq 0x418e28 _D4main7__arrayZ // load x member +193: mov-0x8(%rbp),%rcx +197: mov(%rcx),%rsi +200: movabs $0x430ac0,%rdi +210: xor%eax,%eax +212: callq 0x4188e0 printf@plt +217: xor%eax,%eax +219: pop%rbx +220: leaveq +221: retq End of assembler dump. Main stack frame looks follows: -0x30(%rbp):-0x28(%rbp) 3 as a pkey arg to _aaGetX -0x28(%rbp):-0x20(%rbp) pointer to S allocated by _aaGetX -0x20(%rbp):-0x18(%rbp) uninitialized struct - this ptr -0x18(%rbp):-0x10(%rbp) constructed struct passed as rhs to opAssign -0x10(%rbp):-0x08(%rbp) 3 as a pkey arg to _aaGetRvalueX -0x08(%rbp):-0x00(%rbp) pointer to S returned from _aaGetRvalueX It seems that dmd allocates space for two structs, one non-initialized, second initialized, issues call to druntime, then places a call to opAssign with non-initialized as this object with initialized as rhs argument, then writes content on non-initialized to allocated by druntime. So, this looks like a codegen bug. By the way, if the code is compiled with command dmd main -g -release -noboundscheck -version=bug, opAssign call is placed before calling _aaGetX. Very educational - thanks!
Re: Can operators return type?
On Thursday, 29 November 2012 at 16:55:01 UTC, bearophile wrote: Zhenya: It would useful for some my project,if operators could be a template,that return type. D operators are functions, and D functions return values. And in D types are not values (unlike Python and several other languages), unless you use a Typeinfo or something. Maybe if you explain better what you are trying to do someone will be able to suggest you an alternative solution. D is not as flexible as Lisp, but it doesn't lack meta-programming/type-processing capabilities. Bye, bearophile Of course I understand,that type is not value in D.I meant that maybe we can declare non-function template operators.For example: struct MyIntType { alias int type; template opSlice() { alias type opSlice; }
Re: Can operators return type?
Zhenya: For example: struct MyIntType { alias int type; template opSlice() { alias type opSlice; } As you guess, this is not supported in D. Bye, bearophile
Re: Can operators return type?
On Thursday, 29 November 2012 at 21:53:20 UTC, bearophile wrote: Zhenya: For example: struct MyIntType { alias int type; template opSlice() { alias type opSlice; } As you guess, this is not supported in D. Bye, bearophile Thank you,understood(
Newb's questions constructor
Reading 'the book' and it states that D does not allow one to nest construction calls that are not complete. e.g., this() { if (x 1) { this(x); } } will fail. First, I do not know why this is required. It seems to me it would be better to allow one optionally use another constructor if it is desired rather than forcing all paths to use it. Also, It is easy to avoid this by alaising this(...)(using member functions that this(...) wraps). This, then is exactly the same semantically above but avoids the error: this() { if (x 1) { thiswrapper(x); } } this(double x) { thiswrapper(x); } (so, the constraint in D only increases code bloat as far as I can tell and, hence, unnecessary) Second, steaming from this issue with constructors, how can we get the address of a constructor, or alternative, store it in a delegate/function: class Test { static void function(Test, double) thiswrapper; this() { thiswrapper = this(double); if (x 1) { thiswrapper(x); } } this(double x) { } } The point of the example code(only an example, I know it is rather useless but so are babies, right?) is to simply do the same the previous example but sort of backwards. The previous example has thiswrapper being wrapped by this(double) while in this case thiswrapper wraps this(double). They will will have virtually identical semantics with different syntax. The second case allows us to solve the original problem a bit more logical. (in fact, if we had some type of multi-function pointer that allowed overloads we could, say, assign all the constructor functions to thiswrapper and let the compiler choose the appropriate one) In any case the second question involves assigning functions to function pointers/delegates, specifically the constructor functions. I guess it would be the a similar problem if I wanted to assign a function pointer to a member of a class from a pointer to that class. class Test { void mymethod(...){} void mymethod(){}} void function(...) mymethodptr = t-mymethod; (which should be the same as Test.mymethod?) Thanks
Templated Function pointers
I need to store a templated function in a function pointer, how can I do this? e.g., void function(double) myfuncptr; void myfunc(double d) { } myfuncptr = myfunc; Now I would like to use a template parameter instead of double. In C++ one can do this by using boosts binding's and function types. For example, I want something like this void function(F)(F) funcptr; void Bind(T)(void function(T)(T) v) { funcptr = v; // F is sort of deduced automatically as being T. Obviously problematic but effectively what I want to do. } This way I can bind to any function that takes a single type parameter and returns a void. void function(F) myfuncptr; // F is undefined void myfunc(T)(T d) { } // myfuncptr = myfunc; To do this using boost I would simply bind the parameter so myfuncptr would not depend on an arbitrary type. I need a rather performant way to do this too.
prune with dirEntries
Is there a way to walk files with std.file.dirEntries such that certain directories are skipped (i.e. how to avoid .git entirely/recursively)? Thanks Dan
Re: prune with dirEntries
On Friday, November 30, 2012 01:24:07 Dan wrote: Is there a way to walk files with std.file.dirEntries such that certain directories are skipped (i.e. how to avoid .git entirely/recursively)? You can use std.algorithm.filter on its result. Then when it would iterate to something which doesn't match filter's predicate, it skips it. - Jonathan M Davis
Re: prune with dirEntries
On Friday, 30 November 2012 at 01:13:13 UTC, Jonathan M Davis wrote: On Friday, November 30, 2012 01:24:07 Dan wrote: Is there a way to walk files with std.file.dirEntries such that certain directories are skipped (i.e. how to avoid .git entirely/recursively)? You can use std.algorithm.filter on its result. Then when it would iterate to something which doesn't match filter's predicate, it skips it. - Jonathan M Davis That will do the filtering correctly - but what I was hoping was to actually prune at the directory level and not drill down to the files in of an unwanted directory (e.g. .git). The problem with this and what I'm trying to overcome is accessing lots of files and directories recursively all of which I want to skip. Much like there is a *followSymlink* it would be nice if a predicate were accepted to *followDirectory* in general or some way to cause that. --- static bool desired(string m) { bool unwanted = match(m, _uninterestRe)? true : false; writeln(Is unwanted , m, , unwanted); return !unwanted; } static Regex!(char) _uninterestRe = regex(`\.git\b`); filter!(desired)(dirEntries(root, SpanMode.depth))) { ... }
Re: prune with dirEntries
On Friday, November 30, 2012 02:57:20 Dan wrote: On Friday, 30 November 2012 at 01:13:13 UTC, Jonathan M Davis wrote: On Friday, November 30, 2012 01:24:07 Dan wrote: Is there a way to walk files with std.file.dirEntries such that certain directories are skipped (i.e. how to avoid .git entirely/recursively)? You can use std.algorithm.filter on its result. Then when it would iterate to something which doesn't match filter's predicate, it skips it. - Jonathan M Davis That will do the filtering correctly - but what I was hoping was to actually prune at the directory level and not drill down to the files in of an unwanted directory (e.g. .git). The problem with this and what I'm trying to overcome is accessing lots of files and directories recursively all of which I want to skip. Much like there is a *followSymlink* it would be nice if a predicate were accepted to *followDirectory* in general or some way to cause that. --- static bool desired(string m) { bool unwanted = match(m, _uninterestRe)? true : false; writeln(Is unwanted , m, , unwanted); return !unwanted; } static Regex!(char) _uninterestRe = regex(`\.git\b`); filter!(desired)(dirEntries(root, SpanMode.depth))) { ... } You can use the glob matching overload then: auto dirEntries(string path, string pattern, SpanMode mode, bool followSymlink = true) I don't really know how to use it though, so you'll have to read the docs and figure it out. - Jonathan M Davis
Type converter from build in to user type
I have a struct I am trying convert from int's to the type. Since I can't add a opCast overload to an int I don't know how to do it. My opCast convertors in my class do not work for the assignment operator: class myType { opCast, opAssign } mytype = 3; Error that we can't convert an int to myType. While it's very easy to go from a myType to whatever by writing a cast for it(in the class), how do I go from an int to myType(in the class)? For example, I can do mytype = mytype.opCast(3); or mytype.opAssign(3); but these are too verbose to be useful.
Re: Type converter from build in to user type
On Friday, November 30, 2012 03:59:05 js.mdnq wrote: I have a struct I am trying convert from int's to the type. Since I can't add a opCast overload to an int I don't know how to do it. My opCast convertors in my class do not work for the assignment operator: class myType { opCast, opAssign } mytype = 3; Error that we can't convert an int to myType. While it's very easy to go from a myType to whatever by writing a cast for it(in the class), how do I go from an int to myType(in the class)? For example, I can do mytype = mytype.opCast(3); or mytype.opAssign(3); but these are too verbose to be useful. You can put a constructor on your type which takes an int and then use std.conv.to instead of casting. It's generally preferred to use std.conv.to anyway, since it's generally safer (since it allows fewer (no?) unsafe casts and checks conversions in some cases - e.g. whether the value in the int being cast to ubyte will fit in a ubyte). It will also use your opCast if you define one, so you can then use std.conv.to in both directions. - Jonathan M Davis
Re: Type converter from build in to user type
On Friday, 30 November 2012 at 02:59:06 UTC, js.mdnq wrote: I have a struct I am trying convert from int's to the type. Since I can't add a opCast overload to an int I don't know how to do it. My opCast convertors in my class do not work for the assignment operator: class myType { opCast, opAssign } mytype = 3; Error that we can't convert an int to myType. While it's very easy to go from a myType to whatever by writing a cast for it(in the class), how do I go from an int to myType(in the class)? For example, I can do mytype = mytype.opCast(3); or mytype.opAssign(3); but these are too verbose to be useful. Why can't you use opAssign? This works fine: class A { void opAssign(int i) { writeln(i); } } auto a = new A(); a = 1; // prints 1
Re: Type converter from build in to user type
On 11/29/2012 07:24 PM, jerro wrote: On Friday, 30 November 2012 at 02:59:06 UTC, js.mdnq wrote: I have a struct I am trying convert from int's to the type. Since I can't add a opCast overload to an int I don't know how to do it. My opCast convertors in my class do not work for the assignment operator: class myType { opCast, opAssign } mytype = 3; Error that we can't convert an int to myType. While it's very easy to go from a myType to whatever by writing a cast for it(in the class), how do I go from an int to myType(in the class)? For example, I can do mytype = mytype.opCast(3); or mytype.opAssign(3); but these are too verbose to be useful. Why can't you use opAssign? This works fine: class A { void opAssign(int i) { writeln(i); } } auto a = new A(); a = 1; // prints 1 A complete example: import std.conv; class C { int i; this(int i) { this.i = i; } C opAssign(int i) { this.i = i; return this; } int opCast(T : int)() const { return i; } } void main() { auto c = new C(42); c = 43; auto i = to!int(c); assert(i == 43); } Ali
Re: Calls to struct methods and immutable
On 11/27/2012 06:05 AM, Joseph Rushton Wakeling wrote: On 11/27/2012 01:16 PM, Joseph Rushton Wakeling wrote: immutable(Node) idup() pure const @property { auto linkCopy = to!(Link[])(links); immutable ilinks = assumeUnique(linkCopy); return immutable(Node)(id, ilinks); } Actually I'm being overly complicated here as with dynamic arrays I can simply do, immutable(Node) idup() pure const @property { return immutable(Node)(id, links.idup); } ... so the real issue here seems to be that there's no canonical way (that I can find) to idup an _associative_ array. I've forced it pretty hard: :D immutable(Network) idup() pure const @property { Node[uint] nodesCopy; foreach (key, node; nodes) { immutable(Node) nodeCopy = node.idup; nodesCopy[key] = cast(Node)nodeCopy; } immutable imnodes = assumeUnique(nodesCopy); return immutable(Network)(imnodes); } I hope it is safe. :p Ali
Re: prune with dirEntries
On Friday, 30 November 2012 at 01:57:21 UTC, Dan wrote: That will do the filtering correctly - but what I was hoping was to actually prune at the directory level and not drill down to the files in of an unwanted directory (e.g. .git). The problem with this and what I'm trying to overcome is accessing lots of files and directories recursively all of which I want to skip. Much like there is a *followSymlink* it would be nice if a predicate were accepted to *followDirectory* in general or some way to cause that. what about the following? import std.algorithm, std.array, std.regex; import std.stdio, std.file; void main() { auto exclude = regex(r\.git, g); dirEntries(/path/GIT, SpanMode.breadth) .filter!(a = match(a.name, exclude).empty) .writeln(); } I think if you go breadth first, you can filter out the unwanted directories before it delves into them
Re: prune with dirEntries
On Friday, 30 November 2012 at 06:29:01 UTC, Joshua Niehus wrote: I think if you go breadth first, you can filter out the unwanted directories before it delves into them oh wait... it probably still looks through all those dir's. What about this? import std.algorithm, std.regex, std.stdio, std.file; import std.parallelism; DirEntry[] prune(string path, ref DirEntry[] files) { auto exclude = regex(r\.git|\.DS_Store, g); foreach(_path; taskPool.parallel(dirEntries(path, SpanMode.shallow) .filter!(a = match(a.name, exclude).empty))) { files ~= _path; if (isDir(_path.name)) { prune(_path.name, files); } } return files; } void main() { DirEntry[] files; prune(/path, files); foreach(file;files) { writeln(file.name); } }