Temporarily protect array from garbage collection
Is it possible to temporarily prevent the garbage collector from collecting a memory block even if there are no references to it? The use case is as follows: I want to call a C library function which expects to take ownership of a buffer. It looks something like this: alias FreeFunc = extern(C) void function(void*, void*) nothrow; extern(C) void foo(void* buf, size_t len, FreeFunc free, void* ctx) nothrow; Here, 'buf' is a pointer to the buffer, 'len' is the length of the buffer, 'free' is a function to deallocate the buffer when the library is done with it, and 'ctx' is a user-supplied context pointer. Upon deallocation, 'free' receives two parameters; the pointer to the buffer and the context pointer. The latter can be anything, even null, as it is just passed to 'free' and not used for anything else. Here is the problem: I want to be able to use a garbage-collected dynamic array with this function, but I don't want to have to retain a reference to it in my program. (I don't know when the C library will call the free function.) In other words, I want something like this: extern(C) void myFree(void* ptr, void* ctx) { enableGCFor(ptr); } auto arr = new int[123]; disableGCFor(arr); foo(arr.ptr, arr.length, myFree, null); arr = null; Is this at all possible? Thanks, Lars
Re: Temporarily protect array from garbage collection
On Thursday, 24 April 2014 at 20:09:38 UTC, Justin Whear wrote: You can use GC.addRoot() from core.memory before passing the pointer to the C function, then use GC.removeRoot in your myFree function. Perfect, thanks!
Struct size
Say I have two structs, defined like this: struct A { /* could contain whatever */ } struct B { A a; } My question is, is it now guaranteed that A.sizeof==B.sizeof, regardless of how A is defined (member variable types, alignment, etc.)? More to the point, say I have a function foo() which looks like this: extern(C) void foo(A* ptr, size_t len); Is it now guaranteed that I can safely pass it a pointer to an array of Bs? That is, auto arr = new B[10]; foo(cast(A*) arr.ptr, arr.length); Thanks, Lars
Re: Struct size
On Saturday, 19 April 2014 at 12:26:16 UTC, Andrej Mitrovic via Digitalmars-d-learn wrote: On 4/19/14, Lars T. Kyllingstad via Digitalmars-d-learn digitalmars-d-learn@puremagic.com wrote: Say I have two structs, defined like this: struct A { /* could contain whatever */ } struct B { A a; } My question is, is it now guaranteed that A.sizeof==B.sizeof? The best thing to do is add a static assert and then you can relax: That's what I've done, but it would be nice to know the code won't break due to some combination of platform and/or compiler switches I didn't think to test. Anyway, I've played around a bit, and found that a combination of struct and field alignment *can* break my assumption: align(1) struct A { char c; align(1) int i; } struct B { A a; } Now, A.sizeof is 5, while B.sizeof is 8. I'd have to add align(1) to the declaration of B to fix it.
Re: Different NaNs used
On Mon, 27 Jun 2011 16:41:14 -0400, bearophile wrote: This question is related to this thread: http://d.puremagic.com/issues/show_bug.cgi?id=3632 Can you tell me why real.nan and real.init don't contain the same bit patterns? import std.math: isIdentical; void main() { assert(isIdentical(real.nan, real.init)); // this asserts } real.init is a signaling NaN, real.nan is not. I don't know if this is by design, but I suppose it may be: You can quiet a signaling NaN by assigning real.nan to your variable. http://en.wikipedia.org/wiki/NaN#Signaling_NaN -Lars
Re: Advice on threading/fibers/?
On Wed, 15 Jun 2011 23:57:25 +, Justin Whear wrote: Consider the following: You have 10 million data points and you need to apply a multipass algorithm to them. Each pass is like a cellular automata: it can read from the previous pass but it doesn't know the current values. This makes the actual processing of each value trivially parallelizable. The actual operation for each value is fairly simple and cheap (essentially a multidimensional ancestor-child averaging operation). After each value has been operated on once, the pass is complete and the current and old buffers are switched (conceptually, the current buffer can only be written to, the old buffer can only be read--using __gshared here). The number of passes is not fixed; in the course of each value operation, an error is computed. When the worst individual error falls below a certain threshold, the algorithm is finished. Generally this will take between one thousand and ten thousand passes. How would you go about parallelizing this? My thought is to take the map/reduce approach within each pass: each thread/fiber takes a slice of the dataset, makes its modifications, then returns an error summary. These summaries are quickly combined and the algorithm loop decides whether to run again. Each pass shouldn't take more than a second or two, so I'm not sure whether introducing the overhead of spawning, say, 10 threads each pass is worthwhile (times 5000 passes). On the other hand, I have plenty of CPUs to throw at it (at least 16 cores, each with hyperthreading) and am in a situation where as fast as possible is important (while individual datasets may not grow, the number of them is). Any thoughts appreciated. I would recommend you take a look at the new std.parallelism module, which was introduced in the most recent DMD release (2.053): http://www.d-programming-language.org/phobos-prerelease/ std_parallelism.html -Lars
Re: Pure not acting pure.
On Thu, 16 Jun 2011 06:52:45 -0400, Michel Fortin wrote: On 2011-06-15 23:29:46 -0400, Charles McAnany mcana...@rose-hulman.edu said: Ah, so does the compiler figure out which ones are strongly and weakly pure and then optimize as appropriate? Is there a way to indicate that a function is strongly pure? Because it would seem odd to call a function you thought was pure and wind up with a mutated argument. Just make sure all the parameters are either const or immutable or passed by copy and do not contain any pointer or reference. That'll make the function strongly pure, and the compiler will be able optimize. If you want a strongly pure function, the parameters need to be immutable or implicitly convertible to immutable. const references may be mutated elsewhere. -Lars
Re: Pure not acting pure.
On Thu, 16 Jun 2011 17:38:27 +, Charles McAnany wrote: Ok, I think I get it. That cleared it up. =). So, if you have a functioned labelled pure, it's your job to not pass it mutable arguments, but the compiler's job to make sure it doesn't mutate anything not in the arguments. And that's why a strongly pure function can call a weakly pure one - only the first function's internal state can be mutated by a weakly pure function. Thanks! Exactly. :) -Lars
Re: how to migrate to std.datetime
On Mon, 09 May 2011 09:49:04 +0100, Russel Winder wrote: On Sun, 2011-05-08 at 23:52 -0700, Jonathan M Davis wrote: [ . . . ] I could look at writing an article on moving from std.date to std.datetime, I suppose. We already have an article contest going, and it would make sense to put such an article on the site. I suspect many people would be happy if you did do this, but I was thinking more copy and paste the material into a wiki page and then let everyone who has knowledge/interest help refine it. I don't really have anywhere online that I can post anything myself though, let alone links to whatever newsgroup posts might be useful for understanding std.datetime. If there isn't a D/Phobos wiki then now is the time for Those in Authority, to make one so that this sort of material can go up there and be crowd edited. There certainly is: http://prowiki.org/wiki4d/wiki.cgi -Lars
Re: What is put() useful for with regards to dynamic arrays?
On Sat, 30 Apr 2011 00:09:09 -0400, Andrej Mitrovic wrote: import std.range; void main() { int[] a = [1, 2, 3]; a.put(6); assert(a == [2, 3]); a.put([1, 2]); assert(a.length == 0); } Seems kind of odd.. put is implemented as an append method for some custom types, e.g. std.array.appender. But for arrays put just removes Item or RangeLength number of elements from the array. What's the use case for this? This should probably be in a FAQ somewhere. :) http://www.digitalmars.com/d/archives/digitalmars/D/ std.array.put_doesn_t_put_106871.html -Lars
Re: Reading a line from stdin
On Wed, 16 Mar 2011 11:20:43 +0100, spir wrote: On 03/16/2011 06:41 AM, Jesse Phillips wrote: Ali Çehreli Wrote: Right? Is there a better way that I am missing? Thank you, Ali No better way, the stated reason IIRC is that it is easier to remove the new line then to append it back on. May be stated, but it is very wrong! I guess: s = s ~ '\n'; versus if ((str[$-1] == '\n') || (str[$-1] == '\r')) { str = str[0..$-1]; if ((str[$-1] == '\n') || (str[$-1] == '\r')) { str = str[0..$-1]; } } That comparison seems a bit biased. :) This one is more fair: import std.path; ... s ~= linesep; versus import std.string; ... s = s.chomp; -Lars
Re: in/out with -release
On Sat, 05 Mar 2011 18:12:30 +, Lars T. Kyllingstad wrote: On Sat, 05 Mar 2011 10:15:48 -0700, user wrote: On 03/04/2011 09:22 PM, Jonathan M Davis wrote: On Friday 04 March 2011 20:14:32 Kai Meyer wrote: I have an 'enforce' function call in an 'in' block for a function. When I compile with -release -O -inline, the in/out blocks appear to be skipped. It's a simple verification for a dynamic array to not have a length of 0. In debug mode, the test condition hits the enforce in the 'in' block, but in release mode it does not. In both release and debug mode, the same exact enforce function works properly. So am I to understand that -release will skip in/out blocks entirely? Of course. It uses asserts. asserts are disabled in -release. Asserts are for debugging, testing, and verifying code when developing, not for code which is released. So, you get the benefit of the test when you don't have -release and the benefit of speed when you do have -release. If an assertion fails, your code logic is invalid. It's for validating your code, not user input or whatnot. enforce, on the other hand, is not a language primitive. It's not intended for testing or debugging. It's intended to be used in production code to throw an exception when its condition fails. If an enforce fails, that generally means that you had bad input somewhere or that an operation failed or whatnot. It's not intended for testing the logic of your code like assert is intended to do. It's simply a shorthand way to throw an exception when your program runs into a problem. - Jonathan M Davis I don't think I understand your response entirely. I understand that asserts are disabled in -release mode. I understand that enforce is a function that comes with std.exception, and the code isn't hard to follow. What I'm confused about is the in block, and why it is skipped in -release mode. You say It uses asserts. I didn't put an assert in my in block, I put an enforce. So I'm guessing that you are indicating that the in block is treated like an assert, and is disabled with the -release flag. But I think after reading your post you've helped clarify that what I'm checking (that you can't pop an empty stack) based on user input is something I should be checking with an enforce inside the function, and not an assert or enforce inside the in block. I still think I would like it if you could be a little more explicit about the in/out blocks. Are they always disabled entirely (skipped) with -release, or just certain things? Thanks for your help! -Kai Meyer That's right. in, out and invariant blocks are not included in release mode. -Lars It's documented here, by the way: http://www.digitalmars.com/d/2.0/dmd-linux.html#switches (Scroll down to -release.) -Lars
Re: Two questions about %a
On Wed, 02 Mar 2011 13:35:11 +0100, Magnus Lie Hetland wrote: First question: I just noticed that writefln(%a, 1.2) writes 0x1.3p+0, while writeln(format(%a, 1.2)) (that is, with std.string.format) writes 0x9.8p-3 ... wouldn't it be nice to be consistent here? (The former is what printf in gcc gives.) Or am I missing a difference in functionality? Hm, that's weird. I'm pretty sure writefln() is doing the right thing here, since that's what printf() does. I've had a look at the code for format(), and it looks to me like it is using some old formatting code that is being phased out. I've created a bug report for this, and will look into fixing it shortly: http://d.puremagic.com/issues/show_bug.cgi?id=5687 Second question: Just to make sure, this *is* an exact representation of the underlying floating-point number? (I.e., if that'w what I'm after, using %a *is* the way to go?) Yes, that's right. -Lars
Re: Version very simple?
On Sun, 27 Feb 2011 15:52:01 +0100, simendsjo wrote: I'm having some problems grokking version. How would I translate this simple C macro? #if !defined(IDENT) || !defined(IDENT2) I've tried the following: version(!IDENT) identifier or integer expected, not ! !version(IDENT) Declaration expected, not '!' version(IDENT || IDENT2) found '||' when expecting ')' version(IDENT) || version(IDENT2) Declaration expected, not '||' This is just plain ugly: version(IDENT) { } else { version = NOT_IDENT_OR_IDENT2; } version(IDENT2) { } else { version = NOT_IDENT_OR_IDENT2; } version(NOT_IDENT_OR_IDENT2) { // Finally } Here's one nice solution to your problem: http://www.digitalmars.com/d/archives/digitalmars/D/ Improving_version_..._119799.html#N119846 Basically, he defines an isVersion() template which is true if the current version is enabled, and false if not. -Lars
Re: %x and floats
On Thu, 24 Feb 2011 13:27:39 -0500, Trass3r wrote: Why doesn't this work: import std.stdio; void main() { float a,b=0; writefln(%x %x, a, b); } std.format.FormatError: std.format floating That is because %x is for formatting integers. If you want a hex representation of a floating-point number, use %a. http://www.digitalmars.com/d/2.0/phobos/std_format.html -Lars
What is -nofloat good for?
The dmd help text says the following about the -nofloat switch: -nofloat do not emit reference to floating point What does this mean? What is -nofloat good for? -Lars
Re: Is std.array.replace supposed to work with char[]?
On Sun, 20 Feb 2011 15:23:29 -0500, Steven Schveighoffer wrote: On Sun, 20 Feb 2011 14:51:10 -0500, bearophile bearophileh...@lycos.com wrote: Jacob Carlborg: Every time I try to use D2 it's just a PITA to use. I've used D1 and Tango for several years and had no problem with that. I use this thread to ask regarding one specific little problem I have with strings. I want to generate a random string of AB using the array, map, etc, this looks like a possible implementation (in std.random there is no choice() function yet): import std.stdio, std.random, std.string, std.algorithm, std.range; void main() { auto m = map!((i){ return AB[uniform(0,2)]; })(iota(10)); string s = join(array(m)); writeln(s); } It gives this error: ...\dmd\src\phobos\std\array.d(62): Error: result[i] isn't mutable test.d(5): Error: template instance std.array.array!(Map!(__dgliteral1,Iota!(int,uint))) error instantiating What's the right way to write it in D? The same code in Python2.x: from random import choice s = .join(choice(AB) for _ in xrange(10)) print s Just a blind guess, I have not tested, but maybe it's because the compiler is using const(char) as the return type for your delegate literal since you never specify one? It's probably using immutable(char) since that's the element type of AB. -Lars
Re: rdmd problems (OS X Leopard, DMD 2.052)
On Mon, 21 Feb 2011 12:18:54 +0100, Magnus Lie Hetland wrote: On 2011-02-20 19:22:20 +0100, Magnus Lie Hetland said: On 2011-02-19 22:25:31 +0100, Nick Sabalausky said: [snip] Unfortunately, rdmd doesn't seem to have gotten much attention lately. I've had a few patches for it sitting in bugzilla for a number of months. (Not that I'm complaning, I realize there's been other priorities.) I see. Kind of surprising, given that rdmd is distributed in the official DMD zip file. But, yeah, no complaints. :) Actually, if you want, you can grab a version of rdmd.d with my patches applied here: http://www.dsource.org/projects/semitwist/browser/trunk/rdmdAlt.d Thanks! Humm. I'm still using the rdmd I had (it seems to work, so as long as I have already compiled it... ;) However: I'm a bit baffled by the --shebang option. What's its purpose, really? If I use rdmd without it in a shebang line, it seems to work fine. If I *do* use --shebang, the code doesn't seem to be compiled/executed at all... It seems like it interprets args[1] as a single string containing all the arguments, splitting it into separate items. That seems well an good -- except (in OS X, at least) it doesn't seem to be needed (I get my arguments just fine without it, and the shebang-line switches work well) ... and it doesn't seem to work (that is, with --shebang, nothing happens). Any thoughts on this? Say you have a file myscript, that starts with the line #!/path/to/interpreter --foo --bar If you run this as ./myscript --hello --world then the args[] received by the interpreter program looks like this: args[0] = /path/to/interpreter args[1] = --foo --bar args[2] = ./myscript args[3] = --hello args[4] = --world This is the case on every shell I've tried on Linux, at least. So if you have multiple rdmd options, it should in principle need --shebang to know that it is being run in a shebang line, so it can expand args[1]. I don't know why it works without --shebang for you, though. :) -Lars
Re: Checking if something is a template specialization?
On Fri, 18 Feb 2011 02:02:51 +, Sean Eskapp wrote: If I have class Bar(T) { } void foo(Y)() { ... } Is there a way to check inside foo() that Y is in some way an instantiation of Bar? Is there a way to find WHICH instantiation it is? void foo(Y)() { static if (is(Y Z == Bar!Z)) { // Here, Z is now an alias to whichever type Bar is // instantiated with. } else { // Z is invalid here. } }
Re: datetime fails with undefined reference
On Fri, 18 Feb 2011 16:38:19 +, Kai Meyer wrote: I can't seem to use std.datetime at all. I get undefined reference on whether I use a StopWatch, or if I just try to compile the unittest. All I have to do is declare a StopWatch: import std.stdio; import std.datetime; void main() { StopWatch sw; } This fails to compile: [kai@worky ~]$ dmd datetime_test.d /usr/lib/gcc/x86_64-redhat-linux/4.5.1/../../../../lib/libphobos2.a (datetime_35c_30e.o): In function `_D3std8datetime7systimeFNeZS3std8datetime5Ticks': std/datetime.d:(.text._D3std8datetime7systimeFNeZS3std8datetime5Ticks +0x1c): undefined reference to `clock_gettime' /usr/lib/gcc/x86_64-redhat-linux/4.5.1/../../../../lib/libphobos2.a (datetime_359_1fe.o): In function `_D3std8datetime5Ticks12_staticCtor5OFNeZv': std/datetime.d:(.text._D3std8datetime5Ticks12_staticCtor5OFNeZv+0x1b): undefined reference to `clock_getres' collect2: ld returned 1 exit status --- errorlevel 1 Am I missing some libraries somewhere? If I 'import core.sys.posix.time, core.sys.posix.sys.time;', parts of dattime work, and others don't. A main with just: writef(%s %s\n, (is(typeof({auto fp = clock_gettime; }; Prints true true, but using them like this gives undefined again: timespec ts; writef(%d\n, clock_getres(CLOCK_REALTIME, ts)); datetime_test.o: In function `_Dmain': datetime_test.d:(.text._Dmain+0x34): undefined reference to `clock_getres' collect2: ld returned 1 exit status --- errorlevel 1 I'm running Fedora 14 x86_64, dmd-2.051-0.i386, glibc-2.13-1.i686. Any ideas? You have to link in librt. Pass the -L-lrt option to DMD and it should work. -Lars
Re: Finding out if T is a specialization of another template
On Fri, 18 Feb 2011 17:16:02 +, Sean Eskapp wrote: I was given this code, to check if Y is a specialization of Bar. How does it work? class Bar(T) { } void foo(Y)() { static if (is(Y Z == Bar!Z)) { // Here, Z is now an alias to whichever type Bar is // instantiated with. } else { // Z is invalid here. } } I'm not sure what you mean by how does it work. If it's the is() expression you're wondering about, it's documented here: http://www.digitalmars.com/d/2.0/expression.html#IsExpression -Lars
Re: datetime fails with undefined reference
On Fri, 18 Feb 2011 10:23:41 -0800, Jonathan M Davis wrote: On Friday, February 18, 2011 10:12:09 Kai Meyer wrote: Great news! Worked like a champ. Is there documentation somewhere that I missed? I would love to be able to answer these questions on my own. I've been stumped on this one for a week :( That should be in the dmd.conf in dmd.2.052.zip. If you're using an old dmd.conf, that would be the problem. Actually, I wouldn't have expected and old dmd.conf to work at all, since the directory structure for the lib folder(s) was changed due to the addition of 64-bit. So, I don't know what the deal with your setup is. Regardless, make sure that your current dmd.conf is either the most up-to-date on or at least based on it. Otherwise, you're going to be running into issues. Well, he could be using a setup similar to me. I don't use dmd.conf at all. Instead I set the DFLAGS environment variable in the startup script of my shell. I think the new dependency should be noted in the changelog. -Lars
Re: Finding out if T is a specialization of another template
On Fri, 18 Feb 2011 20:37:38 +, Sean Eskapp wrote: == Quote from Lars T. Kyllingstad (public@kyllingen.NOSPAMnet)'s article On Fri, 18 Feb 2011 17:16:02 +, Sean Eskapp wrote: I was given this code, to check if Y is a specialization of Bar. How does it work? class Bar(T) { } void foo(Y)() { static if (is(Y Z == Bar!Z)) { // Here, Z is now an alias to whichever type Bar is // instantiated with. } else { // Z is invalid here. } } I'm not sure what you mean by how does it work. If it's the is() expression you're wondering about, it's documented here: http://www.digitalmars.com/d/2.0/expression.html#IsExpression -Lars Ah, yes. I'd checked the is documentation, but whenever I tried using that is expression outside of an if statement, it complained about my usage, so I assumed it had something to do with if statements. Yeah, is() has a few extra features when it's combined with 'static if'. :) -Lars
Re: Git library for checkouts?
On Tue, 15 Feb 2011 21:32:06 +0100, Jacob Carlborg wrote: Maybe a little off topic but does anyone know about a git library, I'll only need to do checkouts? Here is a C library, written by the folks behind GitHub: https://github.com/schacon/libgit -Lars
Re: MD5 hash on a file and rawRead
On Wed, 09 Feb 2011 23:01:47 -0500, Andrej Mitrovic wrote: I'm trying to use the std.md5.sum method. It takes as an argument a digest to output the hash to, and the second argument is plain data. So I'm trying to read an entire file at once. I thought about using rawRead, but I get a runtime exception: auto filename = rC:\file.dat; File file; try { file = File(filename, r); } catch (ErrnoException exc) { return; } ubyte[] buffer; file.rawRead(buffer); error: stdio.d:rawRead must take a non-empty buffer There are no size methods for the File structure (why?). There's a getSize function but it's in std.file, and I can't use it because: auto filename = rC:\file.dat; File file; try { file = File(filename, r); } catch (ErrnoException exc) { return; } ubyte[] buffer = new ubyte[](getSize(filename)); ubyte[16] digest; file.rawRead(buffer); std.md5.sum(digest, buffer); Error: cannot implicitly convert expression (getSize(cast(const(char[]))this._libFileName)) of type ulong to uint I can use the buffered version fine: auto filename = rC:\file.dat; File file; try { file = File(filename, r); } catch (ErrnoException exc) { return; } ubyte[16] digest; MD5_CTX context; context.start(); foreach (ubyte[] buffer; file.byChunk(4096 * 1024)) { context.update(buffer); } context.finish(digest); writefln(MD5 (%s) = %s, filename, digestToString(digest)); But I'd prefer to write simpler code and use rawRead to read the entire file at once. I'm reading really small files, so rawRead should be fine. To read an entire file at once, you should use std.file.read(), or std.file.readText() if it's an UTF encoded text file. Also, why do we have file handling in two different modules? I'd expect to find all file handling ops in std.file, not scattered around Phobos. Let me know if I'm doing something obviously stupid. :) There are actually three modules for file handling, but I think they are nicely separated: - std.file handles files as isolated units, i.e. it reads, writes and manipulates entire files. - std.path manipulates file/directory names as strings, and performs no disk I/O. - std.stdio is for more advanced file I/O, as it lets you open files and manipulate them through the File handle. (This includes reading, writing, seeking, etc.) Hope this clears things up. :) -Lars
Re: How to web programming with D2?
On Thu, 10 Feb 2011 04:29:21 -0500, canalpay wrote: I am trying to write the web framework(but not to write, to gain experience.). Maybe the framework can has got a MVC desing pattern. But first, the D2 is not has got for the web library and I am decided write to library for web. I am writed a function for post and get methods. (I am not tried to functions. But I think, they are works.) POST: https://github.com/canalpay/turna/blob/master/library/post.d GET : https://github.com/canalpay/turna/blob/master/library/get.d Environment variables are easy to write for the function. But How to write a cookie and session? I looked at the codes of tango. However, don't understand.(I'm new to d programming language.) Adam D. Ruppe does a lot of web development in D, and he has created a fairly extensive web-dev library. http://arsdnet.net/dcode/ For cookie/session handling, cgi.d is probably the place to look. -Lars
Re: Dynamic and Static Casting
On Thu, 10 Feb 2011 11:54:02 +, Lars T. Kyllingstad wrote: On Thu, 10 Feb 2011 16:44:12 +0530, d coder wrote: Greetings All I have learnt that D has only one casting operator and that is 'cast'. The same operator assumes different functionality depending on the context in which it he being used. Now I have a situation where I have to downcast an object and I am sure of the objects type and thereby I am sure that the downcast would only be successful. To make the operation faster, in C++ I could have used static_cast operator, thus giving the RTTI a skip. Would this be possible in D? Can I force a static_cast which downcasting? Here's one solution. [...] Ok, bearophile's solution is better, because it has fewer casts. I forgot you can cast to void*. So here's an improved version, with some template constraints to make sure it's only used for class types: T staticCast(T, U)(U obj) if (is(T == class) is(U == class)) { return cast(T) cast(void*) obj; } -Lars
Re: higher-order funcs for ranges (with usual interface)
On Thu, 03 Feb 2011 19:11:04 +0100, spir wrote: On 02/03/2011 02:25 PM, Lars T. Kyllingstad wrote: On Thu, 03 Feb 2011 13:53:44 +0100, spir wrote: On 02/03/2011 01:17 PM, Lars T. Kyllingstad wrote: Why the reluctance to use template constraints? They're so flexible! :) I cannot stand the is() idiom/syntax ;-) Dunno why. Would happily get rid of it in favor of type-classes (built eg as an extension to current interfaces). For instance, instead of: void func (T) (T t) if (is(someConstraint1) is(someConstraint2)) { ... } use: void func (SomeTypeClass T) (T t) { ... } For instance (untested): void func (T) (T t) if (isInputRange(T) is(ElementType!T == E)) -- void func (InputRange!E T) (T t) where InputRange is a (templated) interface / type-class. Type-class checks on /type/ /template/ parameters (as opposed to type checks on regular value parameters) would be performed structurally (as opposed to nominally). D knows how to do this, since that's what it needs to perform when checking is() constraints. I agree that is() is rather ugly. Same with __traits. If you haven't already done so, I suggest you vote up this issue: http://d.puremagic.com/issues/show_bug.cgi?id=3702 Done! (I did not get all the details 'cause no time for a deep look, but anything impulsed by the motivation of getting rid of is() and __traits can hardly be a Bad Thing ;-) What do you think of type classes, as an alternative to Don's proposal in issue #3702. See also Type Classes as Objects and Implicits: http://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf Anyway, you can hide is()'s ugliness in the most common cases, though, by defining new templates. For instance, I wouldn't mind having the following in std.range as an overload of isInputRange: template isInputRange(R, T) { enum isInputRange = isInputRange!R is(ElementType!R == T); } Then, you'd simply write void func(R)(R range) if (isInputRange!(R, E)) { ... } -Lars A great improvement, indeed. While we're at defining a set of constraints in a template, let us make it an interface / type-class that the E must (structurally) satisfy, and just write: void func(InputRange!E R)(R range) { ... } What do you think? Note: a template is not always required, I guess: void writeElements (Iterable Elements) (Elements elements) { foreach (element, elements) { write(element,' '); } } (In this case, because write is itself generic.) How would you deal with the case where the input must satisfy more than one concept/constraint? I mean, for the simple case where you say R must be an input range of E, sure, type classes/concepts are cleaner. But what about the case where, say, you want R to be an infinite random access range that supports slicing? With template constraints it's simple: void doStuff(R)(R someRange) if (isRandomAccessRange!R isInfinite!R hasSlicing!R) { ... } Now, I'm no expert on concepts at all---my main sources of information about them are superficial comments on the D newsgroup and a quick browse of the Wikipedia page---but it seems to me that you'd have to define a new concept for each such combination of constraints. Or? -Lars
Re: default '==' on structs
On Wed, 02 Feb 2011 17:35:50 +0100, spir wrote: On 02/02/2011 04:20 PM, Lars T. Kyllingstad wrote: On Wed, 02 Feb 2011 15:55:53 +0100, spir wrote: Hello, What are the default semantics for '==' on structs? I ask this because I was forced to write opEquals on a struct to get expected behaviour. This struct is basically: struct Lexeme { string tag; string slice; Ordinal index; } Equal Lexeme's compare unequal using default '=='. When I add: const bool opEquals (ref const(Lexeme) l) { return ( this.tag == l.tag this.slice == l.slice this.index == l.index ); } then all works fine. What do I miss? I think the compiler does a bitwise comparison in this case, meaning that it compares the arrays' pointers instead of their data. Related bug report: http://d.puremagic.com/issues/show_bug.cgi?id=3433 -Lars Thank you, Lars. In fact, I do not really understand what you mean. But it helped me think further :-) Two points: * The issue reported is about '==' on structs not using member opEquals when defined, instead performing bitwise comparison. This is not my case: Lexeme members are plain strings and an uint. They should just be compared as is. Bitwise comparison should just work fine. Also, this issue is marked solved for dmd 2.037 (I use 2.051). Yeah, but I would say it isn't really fixed. It seems that the final decision was that members which define opEquals() are compared using opEquals(), while all other members are compared bitwisely. But built-in dynamic arrays can also be compared in two ways, using '==' (equality) or 'is' (identity, i.e. bitwise equality). Struct members which are dynamic arrays should, IMO, be compared using '==', but apparently they are not. * The following works as expected: struct Floats {float f1, f2;} struct Strings {string s1, s2;} struct Lexeme { string tag; string slice; uint index; } unittest { assert ( Floats(1.1,2.2) == Floats(1.1,2.2) ); assert ( Strings(a,b) == Strings(a,b) ); assert ( Lexeme(a,b,1) == Lexeme(a,b,1) ); } This shows, if I'm right: 1. Array (string) members are compared by value, not by ref/pointer. 2. Comparing Lexeme's works in this test case. Nope, it doesn't show that, because you are assigning literals to your strings, and DMD is smart enough to detect duplicate literals. string s1 = foo; string s2 = foo; assert (s1.ptr == s2.ptr); That is actually pretty cool, by the way. :) Here's an example to demonstrate my point: import std.stdio; struct T { string s; } void main(string[] args) { auto s1 = args[1]; auto s2 = args[2]; auto t1 = T(s1); auto t2 = T(s2); if (s1 == s2) writeln(Arrays are equal); else writeln(Arrays are different); if (t1 == t2) writeln(Structs are equal); else writeln(Structs are different); } If run with the arguments foo bar it prints: Arrays are different Structs are different If run with the arguments foo foo it prints: Arrays are equal Structs are different -Lars
Re: higher-order funcs for ranges (with usual interface)
On Thu, 03 Feb 2011 13:05:00 +0100, spir wrote: On 02/03/2011 08:41 AM, Lars T. Kyllingstad wrote: On Wed, 02 Feb 2011 18:38:02 +0100, spir wrote: I guess the only solution would be for the compiler to support a kind of reange type syntax? I'm not sure I understand what you mean here. Perhaps you're looking for something like concepts, which have been discussed for both D and C++0x but rejected in both languages: http://en.wikipedia.org/wiki/Concept_%28generic_programming%29 Yes, I know about concepts ;-) (and typestates, and such). That's not what I mean but I could not find how to express it. What I have in mind is a way to simply express range of T just like array of T is expressed by T[]. But indeed the issue is there is only one type of array of T, while there are an infinity of types of ranges of T. Your solution below is a good alternative. Anyway, if the source and target range are of the same (known) kind, something like this should work: struct MyRange(T) { ... } MyRange!Out map(In, Out)(MyRange!In input, Out delegate(In) f) { ... } If they are of different kinds, but still known, this should work: struct MySourceRange(T) { ... } struct MyTargetRange(T) { ... } MyTargetRange!Out map(In, Out) (MySourceRange!In input, Out delegate(In) f) { ... } Note that I am only talking about what the compiler should be able to figure out through IFTI (implicit function template instantiation), and not about actual implementation. Right, this is more or less what I was looking for. And I think I can restrict cases to ranges beeing of the same kind. If necessary, the result can then be mapped onto another kind of range (hopefully lazily). The only un-workaround-able situation is, I guess, when the source range is infinite ;-) Why the reluctance to use template constraints? They're so flexible! :) -Lars
Re: higher-order funcs for ranges (with usual interface)
On Thu, 03 Feb 2011 13:53:44 +0100, spir wrote: On 02/03/2011 01:17 PM, Lars T. Kyllingstad wrote: Why the reluctance to use template constraints? They're so flexible! :) I cannot stand the is() idiom/syntax ;-) Dunno why. Would happily get rid of it in favor of type-classes (built eg as an extension to current interfaces). For instance, instead of: void func (T) (T t) if (is(someConstraint1) is(someConstraint2)) { ... } use: void func (SomeTypeClass T) (T t) { ... } For instance (untested): void func (T) (T t) if (isInputRange(T) is(ElementType!T == E)) -- void func (InputRange!E T) (T t) where InputRange is a (templated) interface / type-class. Type-class checks on /type/ /template/ parameters (as opposed to type checks on regular value parameters) would be performed structurally (as opposed to nominally). D knows how to do this, since that's what it needs to perform when checking is() constraints. I agree that is() is rather ugly. Same with __traits. If you haven't already done so, I suggest you vote up this issue: http://d.puremagic.com/issues/show_bug.cgi?id=3702 Anyway, you can hide is()'s ugliness in the most common cases, though, by defining new templates. For instance, I wouldn't mind having the following in std.range as an overload of isInputRange: template isInputRange(R, T) { enum isInputRange = isInputRange!R is(ElementType!R == T); } Then, you'd simply write void func(R)(R range) if (isInputRange!(R, E)) { ... } -Lars
Re: higher-order funcs for ranges (with usual interface)
On Wed, 02 Feb 2011 13:26:39 +0100, spir wrote: Hello, This bit of code for arrays: Out[] map (In,Out) (In[] input, Out delegate (In) f) { Out[] output = new Out[](input.length); foreach (i,item ; input) output [i] = f(item); return output; } unittest { char character (uint code) {return cast(char)code;} uint[] codes = [0x61,0x62,0x63]; // functional style writeln(map(codes, character));// abc // OO style writeln(codes.map(character)); // abc } How to write this for ranges? [...] For ranges, I'm looking for something similar to: Range!Out map (In,Out) (Range!In input, Out delegate (In) f) {...} Indeed, the compiler should understand that Range!T is a type id just like T[]. I don't think it's possible to do it exactly as you describe. I mean, Range in that case can be anything, and you can't always return a range of the same kind. Two possibilities are, you can do it eagerly, Out[] map(Range, In, Out)(Range input, Out delegate(In) f) if (isInputRange!Range is(ElementType!Range : In)) { ... } or you can do it lazily by defining your own map range (untested): struct Map(Range, In, Out) if (isInputRange!Range is(ElementType!Range : In) { Range input; Out delegate(In) f; @property bool empty() { return input.empty; } // Inefficient, should cache front... @property Out front() { return f(input.front); } void popFront() { input.popFront(); } } Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f) if (isInputRange!R is(ElementType!Range : In) { return typeof(return)(input, f); } -Lars
Re: higher-order funcs for ranges (with usual interface)
On Wed, 02 Feb 2011 13:18:07 +, Lars T. Kyllingstad wrote: [...] struct Map(Range, In, Out) if (isInputRange!Range is(ElementType!Range : In) { Range input; Out delegate(In) f; @property bool empty() { return input.empty; } // Inefficient, should cache front... @property Out front() { return f(input.front); } void popFront() { input.popFront(); } } Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f) if (isInputRange!R is(ElementType!Range : In) { return typeof(return)(input, f); } Oops, seems i missed a few closing parentheses on the template constraints. -Lars
Re: default '==' on structs
On Wed, 02 Feb 2011 15:55:53 +0100, spir wrote: Hello, What are the default semantics for '==' on structs? I ask this because I was forced to write opEquals on a struct to get expected behaviour. This struct is basically: struct Lexeme { string tag; string slice; Ordinal index; } Equal Lexeme's compare unequal using default '=='. When I add: const bool opEquals (ref const(Lexeme) l) { return ( this.tag == l.tag this.slice == l.slice this.index == l.index ); } then all works fine. What do I miss? I think the compiler does a bitwise comparison in this case, meaning that it compares the arrays' pointers instead of their data. Related bug report: http://d.puremagic.com/issues/show_bug.cgi?id=3433 -Lars
Re: higher-order funcs for ranges (with usual interface)
On Wed, 02 Feb 2011 18:38:02 +0100, spir wrote: On 02/02/2011 02:18 PM, Lars T. Kyllingstad wrote: On Wed, 02 Feb 2011 13:26:39 +0100, spir wrote: Hello, This bit of code for arrays: Out[] map (In,Out) (In[] input, Out delegate (In) f) { Out[] output = new Out[](input.length); foreach (i,item ; input) output [i] = f(item); return output; } unittest { char character (uint code) {return cast(char)code;} uint[] codes = [0x61,0x62,0x63]; // functional style writeln(map(codes,character));// abc // OO style writeln(codes.map(character)); // abc } How to write this for ranges? [...] For ranges, I'm looking for something similar to: Range!Out map (In,Out) (Range!In input, Out delegate (In) f) {...} Indeed, the compiler should understand that Range!T is a type id just like T[]. I don't think it's possible to do it exactly as you describe. I mean, Range in that case can be anything, and you can't always return a range of the same kind. Right. The output range's ElementType is given by f's return type. As you say, the kind of range may change. Even if it's the same, how could one express that: range_which-elements-are-of-type-T, syntactically and in the param set, just like array_which-elements-are-of-type- is written T[]? Currently, we must (1) declare the range type as template param, which is a bit redondant because the ElementType must also be given, (2) add some 'is' horror code: if (isInputRange!Range is(ElementType!Range : In)) I guess the only solution would be for the compiler to support a kind of reange type syntax? I'm not sure I understand what you mean here. Perhaps you're looking for something like concepts, which have been discussed for both D and C++0x but rejected in both languages: http://en.wikipedia.org/wiki/Concept_%28generic_programming%29 Anyway, if the source and target range are of the same (known) kind, something like this should work: struct MyRange(T) { ... } MyRange!Out map(In, Out)(MyRange!In input, Out delegate(In) f) { ... } If they are of different kinds, but still known, this should work: struct MySourceRange(T) { ... } struct MyTargetRange(T) { ... } MyTargetRange!Out map(In, Out) (MySourceRange!In input, Out delegate(In) f) { ... } Note that I am only talking about what the compiler should be able to figure out through IFTI (implicit function template instantiation), and not about actual implementation. Two possibilities are, you can do it eagerly, Out[] map(Range, In, Out)(Range input, Out delegate(In) f) if (isInputRange!Range is(ElementType!Range : In)) { ... } OK. or you can do it lazily by defining your own map range (untested): struct Map(Range, In, Out) if (isInputRange!Range is(ElementType!Range : In) { Range input; Out delegate(In) f; @property bool empty() { return input.empty; } // Inefficient, should cache front... @property Out front() { return f(input.front); } void popFront() { input.popFront(); } } That's similar to what I did. Map!(Range, Out) map(Range, In, Out)(Range input, Out delegate(In) f) if (isInputRange!R is(ElementType!Range : In) { return typeof(return)(input, f); } What's the point of map, then? My version initially had a 'MapRange' defined as static struct template inside map, but then map just instanciated it, so I suppressed map alltogether, letting the user write: auto r2 = MapRange!(R1, In, Out)(input, f); which is not more complicated than calling the func, I guess. map() is just a helper function. Unlike struct literals/constructors, functions can make use of IFTI, which makes for much prettier code: // The range from my example, without map() auto result = Map!(SomeRange!int, int, bool)(someRange, someDelegate); // The range from my example, with map() auto result = map(someInputRange, someDelegate); This has become a quite common idiom in Phobos. std.range, for instance, is littered with helper functions like this: Retro, retro() Stride, stride() Chain, chain() ... The list goes on. -Lars
Re: std.format example not working
On Fri, 28 Jan 2011 23:30:06 -0500, Akakima wrote: Firt, i would like to know if you are interested in receiving comments an bug reports for DMD V1. D1 bugs are still fixed, so bug reports are welcome. http://d.puremagic.com/issues/ D1 has been declared stable, though, so there is usually no point in submitting enhancement requests for it. If yes, then the following example does not work: http://www.digitalmars.com/d/1.0/phobos/std_format.html import std.c.stdio; import std.format; void formattedPrint(...) { void putc(char c) {fputc(c, stdout);} std.format.doFormat(putc, _arguments, _argptr); } declaring: void putc(dchar c) fixes the problem. That's a bug in the documentation, please report. :) Also to a D newbee like me, _arguments and _argptr are confusing. _arginfo or _argtype is more significant. _argptr could be _arglist or _argvalue or _arguments Those names would be a better fit to the explanations given. That, on the other hand, would be a breaking change, so it won't happen. -Lars
Re: __gshared static versus static __gshared
On Sat, 29 Jan 2011 08:47:21 +, %u wrote: Is this a bug? __gshared static i; makes i be thread-local, while static __gshared i; makes it be shared. If that's the case, then it is definitely a bug. The order of attributes shouldn't matter. -Lars
Re: non-constant error for module AAs
On Mon, 24 Jan 2011 10:45:03 -0500, Andrej Mitrovic wrote: Is this a bug? import std.stdio; string[string] values = [abc:abc, def:def]; void main() { string[string] values2 = [abc:abc, def:def]; } test.d(3): Error: non-constant expression [abc:abc,def:def] What's non-constant about that expression? My guess would be that using an AA literal is just syntax sugar for calling an AA construction function, and that said function isn't CTFEable. When you specify an initial value for a global, that value must be a compile-time constant. If it's not, as in this case, the correct thing to do is to use a module constructor: string[string] values; static this() { values = [ abc:abc, def:def ]; } It is ONLY a good idea to use an enum array if you know you will be doing all lookups at compile time. If the key you're looking for is just known at run time, the AA will be constructed anew for each lookup (I think), which is hideously expensive. enum string[string] values = [ abc:def, ghi:jkl ]; // This is fine, because it is done at compile time. // It's essentially the same as: auto s = def; auto s = values[abc]; // This is a no-no, because it evaluates to something // like: auto aa = values; auto s = aa[key]; auto key = abc; auto s = values[key]; Here's an example program that demonstrates the difference. On my machine, the enum AA version takes 22x longer than the normal AA version. import std.datetime, std.stdio; enum string[string] enumAA = [ abc : abc, def : def ]; string[string] normalAA; static this() { normalAA = [ abc : abc, def : def ]; } void main() { enum max = 10_000_000; StopWatch sw; string lookup1 = abc; string lookup2 = def; sw.start(); foreach (i; 0 .. max) { auto a = enumAA[lookup1]; auto b = enumAA[lookup2]; } sw.stop(); writeln(sw.peek().seconds); sw.reset(); sw.start(); foreach (i; 0 .. max) { auto a = normalAA[lookup1]; auto b = normalAA[lookup2]; } sw.stop(); writeln(sw.peek().seconds); }
Re: How to use std.bind?
On Mon, 17 Jan 2011 17:03:15 +, Sean Eskapp wrote: I used to use boost::bind all the time, but std.bind has me stumped, as I keep getting static asserts with a cryptic argument has no parameters message. At this point, the code is just: class Foo { void bar(int i) { writeln(i); } } void main() { auto foobar = new Foo; bind(foobar.bar, 5)(); } I've tried a myriad of different ways, but keep coming up with the same error. Using bindAlias gives me an error that std.bind.bindAlias(alias FT) is not a function template. I'm using DMD v2.051 on a Windows platform. Help anybody? Like BlazingWhitester said, std.bind is scheduled for deprecation. (It will be marked as such starting with the next DMD release.) It is a relic from D1, and I don't think it has worked well with D2 for quite a while. Luckily, you don't need it at all. You can do the same thing with D2's built-in features, such as nested functions and lambdas. // Lambda example int add2(int i) { return i + 2; } void main() { auto seven = () { return add2(5); }; assert (seven() == 7); } -Lars
Re: std.container.Array/RefCounted(T) leaking memory?
On Tue, 18 Jan 2011 01:16:51 +, %u wrote: I find it very hard to believe that struct dtors are never called. Sorry, that part was my bad -- last time I checked, they didn't get called, but maybe my example was too complicated, since they did get called for a *simple* example. However, here's a situation in which no postblit or destructor is called whatsoever: import std.stdio; struct S { this(int dummy) { writeln(ctor); } this(this) { writeln(postblit); } ~this() { writeln(dtor); } } S test(int depth) { return depth 0 ? test(depth - 1) : S(0); } int main(string[] argv) { test(3); } That would be bug 3516, wouldn't it? http://d.puremagic.com/issues/show_bug.cgi?id=3516 -Lars
Re: Memory mapped IO
On Sun, 09 Jan 2011 22:44:44 -0800, Dan Olson wrote: I'm exploring D for embedded work as a nice alternative to C/C++ for the 32-bitters and am finding it has a nice set of features. But, what is the best way handle memory mapped IO? I don't see volatile like in C. Is writing asm {} the best way to ensure memory access? Thanks, Dan Olson Would std.mmfile be what you need? http://www.digitalmars.com/d/2.0/phobos/std_mmfile.html -Lars
Re: auto declarations
On Fri, 07 Jan 2011 16:30:24 -0800, Jonathan M Davis wrote: On Friday, January 07, 2011 13:32:42 Ellery Newcomer wrote: auto a = 1, b = null; int a = 1, *b = null; [...] [...] However, I'm vere suprised that the first one succeeds. I think that it should be reported as a bug. All variables declared on the same line are supposed to have the same type. If I remember correctly, TDPL explicitly states that you may use automatic type inference to declare variables of different types in one line. -Lars
Re: Memory mapped IO
On Mon, 10 Jan 2011 08:38:15 -0800, Dan Olson wrote: Lars T. Kyllingstad pub...@kyllingen.nospamnet writes: On Sun, 09 Jan 2011 22:44:44 -0800, Dan Olson wrote: I'm exploring D for embedded work as a nice alternative to C/C++ for the 32-bitters and am finding it has a nice set of features. But, what is the best way handle memory mapped IO? I don't see volatile like in C. Is writing asm {} the best way to ensure memory access? Thanks, Dan Olson Would std.mmfile be what you need? http://www.digitalmars.com/d/2.0/phobos/std_mmfile.html -Lars Ok, thanks. So I see that is a wrapper for mmap. So that would be good for user space code running on top of posix or win32. But... Ah, I should have read your post more closely. I just saw memory mapped IO and latched onto that. :) I'm more interested in the general embedded case with a small OS or no OS (just ISRs and main loop). I'm betting without volatile, asm {} is the next best thing for tickling a controllers peripheral registers? Yes/No? I searched the news groups and saw there used to be a volatile. But it looks like it was done away with because of how it was misused (like C volatile) for thread sharing. But this is different. This is just telling the compiler not to optimize away an access. AFAIK, that's right. The compiler does not optimise across asm {} blocks. -Lars
Re: Why does the example on page 8 of TDPL work without importing std.algorithm for splitter?
On Mon, 03 Jan 2011 17:18:34 -0600, Ellery Newcomer wrote: If you're importing some other phobos module, I would guess an instance of this bug: http://d.puremagic.com/issues/show_bug.cgi?id=314 On 01/03/2011 10:56 AM, Bryce Watkins wrote: However when I use splitter in my code it works without having imported std.algorithm. That's right. std.string does a public selective import of startsWith() and endsWith() from std.algorithm, and bug 314 causes the whole module to be imported publically. 314 is a huge, gaping hole in the module system. AFAIK, it's a high- priority bug, but also one that is very difficult to fix for some reason. -Lars
Re: string comparison
On Sun, 19 Dec 2010 07:01:30 +, doubleagent wrote: Andrei's quick dictionary illustration [in his book, 'The D Programming Language'] doesn't seem to work. Code attached. That's strange. I ran the example you posted using DMD 2.050 myself, and it works for me. Are you 100% sure that you are running this version, and that it is not using an outdated Phobos version (from an older installation, for instance)? One suggestion: Try replacing the next-to-last line with this: dictionary[word.idup] = newId; The 'word' array is mutable and reused by byLine() on each iteration. By doing the above you use an immutable copy of it as the key instead. On my computer, with d2-0.5.0, I got the following output while testing. andrei 0 andrei andrei 1 andrei Also, why doesn't 'splitter' show up on the site's documentation of std.string? And what advantage does 'splitter(strip(line))' offer over 'split(line)'? splitter is defined in std.algorithm. The fact that it becomes visible when you import std.string is due to bug 314: http://d.puremagic.com/issues/show_bug.cgi?id=314 (std.string is supposed to publically import just a few symbols from std.algorithm, but because of this bug the whole module gets imported publically.) The advantage with splitter is that it is lazy and therefore more efficient. split() is eager and allocates memory to hold the string fragments. -Lars
Re: string comparison
On Mon, 20 Dec 2010 18:44:12 +, doubleagent wrote: Are you 100% sure that you are running this version I have to be. There are no other versions of phobos on this box and 'which dmd' points to the correct binary. dictionary[word.idup] = newId; That fixes it. The 'word' array is mutable and reused by byLine() on each iteration. By doing the above you use an immutable copy of it as the key instead. I REALLY don't understand this explanation. Why does the mutability of 'word' matter when the associative array 'dictionary' assigns keys by value...it's got to assign them by value, right? Otherwise we would only get one entry in 'dictionary' and the key would be constantly changing. This could be related to bug 2954, for which a fix will be released in the next version of DMD. http://d.puremagic.com/issues/show_bug.cgi?id=2954 -Lars
Re: random access-range without lower-power range kinds?
On Tue, 14 Dec 2010 09:09:33 +0100, spir wrote: Hello, It seems impossible to define a random-access range (opIndex + length) alone. In fact, I cannot have it used by the language. Am I missing something? Random-access looks enough to provide fonctionality for both input and bidirectional ranges without any additional method. Lowering for forward iteration means I guess ;-) for (uint i=0 ; i coll.length ; i++) { element = coll[i]; doSomethingWith(element); } What is the reason for requiring methods of lower-power range types to be defined? (This makes 5 methods!) Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com To avoid the boilerplate, you could write a mixin that defines the iteration primitives for you. mixin template IterationFuncs() { int index; bool empty() { return index == length; } auto front() { return opIndex(index); } void popFront() { ++index; } // ... etc. } Then you'd just have to define opIndex() and length(), and the mixin does the rest for you. struct MyRange(T) { T opIndex(int i) { ... } @property int length() { ... } mixin IterationFuncs!(); } (I haven't tested the code above, so it probably has bugs, but you get the point.) -Lars
Re: Passing functions to functionals
On Tue, 30 Nov 2010 18:49:56 +0300, Dmitry Olshansky wrote: On 30.11.2010 14:59, Lars T. Kyllingstad wrote: In my library I have a lot of functionals (functions that take other functions as parameters). Here is an example that shows the style I use to define them: // Example: Evaluate the function/delegate/functor f at x. auto eval(F, X)(F f, X x) { return f(x); } // Test void main() { int add2(int i) { return i + 2; } assert (eval(add2, 1) == 3); } In other words, the function is passed as a run-time parameter. I've seen this (or similar) style used in Phobos, but there, I've also noted that functions are sometimes passed as template alias parameters: // Same as above, using template alias parameter. auto eval(alias f, X)(X x) { return f(x); } // Test void main() { int add2(int i) { return i + 2; } assert (eval!add2(1) == 3); } I'd be grateful if people would share their knowledge of the pros and cons of each method. For instance, are there any situations where template alias parameters don't work? Thanks, -Lars alias parameters must be know/computable at compile time, quick example on what you can't do: import std.stdio; auto eval(F, X)(F f, X x) { return f(x); } auto eval2(alias f,X)(X x){ return f(x); } auto summator(int k){ int f(int val){ return k + val; } return f; } // Test void main() { int add2(int i) { return i + 2; } int traceAdd2(int i){ writeln(i, -- ,i+2); return i+2; } int delegate(int) getAdd2(){ writeln(Getting add2); return add2; } assert(eval(add2, 1) == 3); assert(eval2!add2(1) == 3); assert(eval(summator(2),1) == 3); //Next one fails with //Error: closures are not yet supported in CTFE //Error: cannot evaluate summator(2) at compile time //assert(eval2!(summator(2))(1) == 3); assert(eval(traceAdd2,1) == 3); assert(eval2!traceAdd2(1) == 3); //side effect in call is no problem assert(eval(getAdd2,1) == 3); //Next one fails with //Error: cannot evaluate writeln(Getting add2) at compile time //Error: cannot evaluate getAdd2() at compile time //assert(eval2!(getAdd2())(1) == 3); } That's a very good point, and pretty much settles it for me. I'll stay away from alias parameters, then. Thanks! -Lars
Passing functions to functionals
In my library I have a lot of functionals (functions that take other functions as parameters). Here is an example that shows the style I use to define them: // Example: Evaluate the function/delegate/functor f at x. auto eval(F, X)(F f, X x) { return f(x); } // Test void main() { int add2(int i) { return i + 2; } assert (eval(add2, 1) == 3); } In other words, the function is passed as a run-time parameter. I've seen this (or similar) style used in Phobos, but there, I've also noted that functions are sometimes passed as template alias parameters: // Same as above, using template alias parameter. auto eval(alias f, X)(X x) { return f(x); } // Test void main() { int add2(int i) { return i + 2; } assert (eval!add2(1) == 3); } I'd be grateful if people would share their knowledge of the pros and cons of each method. For instance, are there any situations where template alias parameters don't work? Thanks, -Lars
Why is 'scope' so weak?
If I've understood things correctly, by marking a delegate parameter with 'scope' you tell the compiler not to create a true closure for the delegate. Effectively you're saying I promise not to escape this delegate, so you don't need to copy its context to the heap. In brief, my question is: Why doesn't the compiler enforce this promise? In particular, why is 'scope' not a type constructor? (Note that this is mostly a question out of curiosity, and not really a proposal for a new feature. I imagine it has been discussed in the past and rejected for some reason.) Considering that the compiler enforces proper use of pure, nothrow, const, and all those other things, it doesn't seem much harder to do the same with scope. As an example, I really can't see a reason why obviously wrong code like this should be allowed: void delegate() globalDg; void foo(scope void delegate() dg) { globalDg = dg; } Here's a slightly less obvious example, which also compiles successfully: void foo(void delegate() dg); // Who knows what this does? void bar(scope void delegate() dg) { foo(dg); } -Lars
Re: delegate vs function
On Tue, 23 Nov 2010 13:15:46 +0100, spir wrote: Hello, alias void function (int) F; alias void delegate (int) D; void fnFunc (F f, int i) {f(i);} void dgFunc (D d, int i) {d(i);} void writeOut (int i) {writeln(i);} void test () { void writeIn (int i) {writeln(i);} fnFunc(writeOut, 1); dgFunc(writeIn, 1); //~ fnFunc(writeIn, 1);// error (expected a func, got a delegate...) //~ dgFunc(writeOut, 1); // error (... and conversely) } If a function is defined at the module's toplevel and then passed (via a pointer) to a higher-order func that expects a function, al works fine. But if it is defined inside a function, then the pointer is automatically typed as delegate, even if the function does not use any variable in scope, and I get an error. Mark the function as 'static', like this: static void writeIn(int i) { ... } Then the compiler even ensures that it doesn't use any symbols from the enclosing scope. Conversely, if the higher order func is defined to expect a delegate, then it fails if I pass a func defined at the top-level. How to solve this? Use std.functional.toDelegate(), like this: dgFunc(toDelegate(writeOut), 1); (For some reason the documentation for toDelegate() seems to be missing from the D web site, but I don't know why. I'll look into it.) -Lars
Re: delegate vs function
On Tue, 23 Nov 2010 12:25:18 +, Lars T. Kyllingstad wrote: (For some reason the documentation for toDelegate() seems to be missing from the D web site, but I don't know why. I'll look into it.) Ah, found it: http://d.puremagic.com/issues/show_bug.cgi?id=2581 -Lars
Re: Why is 'scope' so weak?
On Tue, 23 Nov 2010 13:46:19 +0100, Lutger Blijdestijn wrote: Lars T. Kyllingstad wrote: If I've understood things correctly, by marking a delegate parameter with 'scope' you tell the compiler not to create a true closure for the delegate. Effectively you're saying I promise not to escape this delegate, so you don't need to copy its context to the heap. In brief, my question is: Why doesn't the compiler enforce this promise? In particular, why is 'scope' not a type constructor? (Note that this is mostly a question out of curiosity, and not really a proposal for a new feature. I imagine it has been discussed in the past and rejected for some reason.) Considering that the compiler enforces proper use of pure, nothrow, const, and all those other things, it doesn't seem much harder to do the same with scope. As an example, I really can't see a reason why obviously wrong code like this should be allowed: void delegate() globalDg; void foo(scope void delegate() dg) { globalDg = dg; } Most likely it is not yet implemented? It's hard to find something on this topic, I couldn't find anything in the spec or tdpl. I did found this one post by Andrei about your question: http://permalink.gmane.org/gmane.comp.lang.d.concurrency/617 Thanks. He only says that ...too many qualifiers make the language quite baroque. Hopefully there is a better reason than that. ;) -Lars
Re: Why is 'scope' so weak?
On Tue, 23 Nov 2010 10:17:08 +, Lars T. Kyllingstad wrote: If I've understood things correctly, by marking a delegate parameter with 'scope' you tell the compiler not to create a true closure for the delegate. [...] I just realised I posted this to the wrong group. I'll repost to digitalmars.D, so please post answers there as well. -Lars
CTFE of yl2x() and other intrinsics
I thought that the compiler could evaluate all intrinsics at compile time, but this doesn't seem to be the case for std.math.yl2x(). Is my assumption wrong, or is this a bug that should be reported? -Lars
Re: CTFE of yl2x() and other intrinsics
On Mon, 15 Nov 2010 13:03:03 +, div0 wrote: On 15/11/2010 12:12, div0 wrote: On 15/11/2010 11:00, Lars T. Kyllingstad wrote: I thought that the compiler could evaluate all intrinsics at compile time, but this doesn't seem to be the case for std.math.yl2x(). Is my assumption wrong, or is this a bug that should be reported? -Lars Looks like it's not implemented because yl2x isn't in DMC. Dam and I thought it would be an easy one! Still I'll have a play with inline asm and see if it'll work. Sweet, I got it working! I'll submit a patch to bugzilla in a bit. Cool! :) -Lars
Re: 2 bool optional params
On Wed, 10 Nov 2010 08:55:26 +0100, spir wrote: Hello, Is there a way for a func to hold 2 optional params of the same type? void f(int p, bool b1=false, bool b2=false) { writefln(p=%s b1=%s b2=%s, p,b1,b2); } Or is there a workaroud? I'm not sure I understand what you're asking for here. Your example works for me. -Lars
Re: custom exception type
On Fri, 22 Oct 2010 13:00:43 +0200, spir wrote: Hello, Where can one find descriptions of Throwable, Error, Exception? (I mean, how do you even know they exist?) I could finally guess the constructor must have a string parameter used for error output. Well, they should be in the documentation for the 'object' module, but I see that they aren't. Until that is fixed, you can check out the source. Throwable starts at line 1210 here: http://www.dsource.org/projects/druntime/browser/trunk/src/object_.d Exception and Error immediately follow it, but they don't really add anything to Throwable. Also, is it possible to implicitely reuse the superclass's constructor? I had to write: class E : Exception { this (string msg) { super(msg) ; } } E.this performs nothing new. But without it, I get a compiler error: trial.d(7): Error: constructor trial.E.this no match for implicit super() call in constructor Isn't the constructor inherited like other attributes? No. With the exception of a no-argument constructor, which Throwable doesn't have, you have to call it explicitly with super(...). Finally, is it possible to customize the error message construction, using eg tostring? A big issue is that, currently, an exception's message is computed at construction time, even if the exception will never be thrown, or more ccommonly never be output -- because it is caught by a 'catch' clause. In some cases, constructing the message can be costly; some programming schemes may throw huge numbers of exceptions, all caught (or nearly all). Example: in a parsing library, pattern match methods throw an instance of MatchFailure when matching fails. When there is a pattern choice, there may be numerous failures for each success. MatchFailure is just a clean way of signaling this fact (*): each failure exception is caught at a higher level to allow trying the alternative patterns. Since error messages can be rather complicated, constructing them uselessly would multiply parsing time by a rather big factor (in my case, ~ X 30!). I guess tostring is the right feature for this: it would return the exception's textual form, ie the message. (For information, this is how Python works.) I tried to use it, but it seems to be simply ignored. What is the func/method that constructs the text of an exception, eg what is implicitely called by writeln(e);? That would be toString(), not tostring(). -Lars
Re: dmd 2.049 bug with take and SList?
On Wed, 13 Oct 2010 18:06:15 +, Lars T. Kyllingstad wrote: On Wed, 13 Oct 2010 16:46:09 +, Nick Treleaven wrote: Hi, I'm new to D2 ranges but have been following D for some time. I'm posting here because I want to check if I'm doing anything wrong before filing a bug. The code below is a test case I made after hitting the problem in real code. Basically the pyramid recursive function should print out: [1, 2, 3] [1, 2] [1] This works fine when calling with an int[] range, but calling with SList!int seems to make the compiler hang, eating up memory. Should I file a bug? import std.stdio; import std.range; import std.container; void pyramid(Range)(Range items) { if (items.empty) return; writeln(items); auto len = walkLength(items); auto r = take(items, len - 1); pyramid(r); } void main() { /* array version is fine */ int[] arr = [1, 2, 3]; pyramid(arr[]); SList!int list = [1, 2, 3]; pyramid(list[]);/* infinite loop with dmd 2.049 */ } You are creating an infinite recursion of templates. For an array the return type of take() is the same array type. For other ranges, the return type of take() is Take!Range. So when you instantiate pyramid! Range, it instantiates pyramid!(Take!Range), and then pyramid!(Take!(Take! Range)), and so on ad infinitum. A solution could be to make take!(Take!Range)() just return another Take! Range. I can look into that, but you should file a bug report on it so it's not forgotten. -Lars http://d.puremagic.com/issues/show_bug.cgi?id=5052
Re: dmd 2.049 bug with take and SList?
On Thu, 14 Oct 2010 06:54:17 +, Lars T. Kyllingstad wrote: On Wed, 13 Oct 2010 18:06:15 +, Lars T. Kyllingstad wrote: On Wed, 13 Oct 2010 16:46:09 +, Nick Treleaven wrote: Hi, I'm new to D2 ranges but have been following D for some time. I'm posting here because I want to check if I'm doing anything wrong before filing a bug. The code below is a test case I made after hitting the problem in real code. Basically the pyramid recursive function should print out: [1, 2, 3] [1, 2] [1] This works fine when calling with an int[] range, but calling with SList!int seems to make the compiler hang, eating up memory. Should I file a bug? import std.stdio; import std.range; import std.container; void pyramid(Range)(Range items) { if (items.empty) return; writeln(items); auto len = walkLength(items); auto r = take(items, len - 1); pyramid(r); } void main() { /* array version is fine */ int[] arr = [1, 2, 3]; pyramid(arr[]); SList!int list = [1, 2, 3]; pyramid(list[]);/* infinite loop with dmd 2.049 */ } You are creating an infinite recursion of templates. For an array the return type of take() is the same array type. For other ranges, the return type of take() is Take!Range. So when you instantiate pyramid! Range, it instantiates pyramid!(Take!Range), and then pyramid!(Take!(Take! Range)), and so on ad infinitum. A solution could be to make take!(Take!Range)() just return another Take! Range. I can look into that, but you should file a bug report on it so it's not forgotten. -Lars http://d.puremagic.com/issues/show_bug.cgi?id=5052 Fixed. http://www.dsource.org/projects/phobos/changeset/2102
Re: writing
On Thu, 14 Oct 2010 09:58:36 +0200, spir wrote: Hello, write and writeln just write; writef and writefln first format: seems clear. But the latter do not work properly with D strings, and the former do not work without format. Is there a practical way to just write anything to the terminal (without caring of its type)? Is there some rationale about this? Would it be possible to automatically add \0 to D strings passed to write/writeln (can a programmer define a custom func doing this before delegating to builtin funcs, or is it necessarily a job for the compiler?)? And/or what about having writef/writefln use %s as default format (when the first arg is not a string)? I don't understand what you mean. This works just fine: import std.stdio; void main() { string s = Hello world!; writeln(s); } If I'm misunderstanding you, please explain, or perhaps give a code example. -Lars
Re: toString(char*)?
On Mon, 11 Oct 2010 21:46:26 +0200, Lutger wrote: Where can I find the function to convert from c-style string to a normal D string? It used to be toString in std.string, but that one is deprecated. Thanks. import std.conv; const char* cString; string dString = to!string(cString) -Lars
Re: toString(char*)?
On Mon, 11 Oct 2010 22:00:37 +0200, Lutger wrote: Lars T. Kyllingstad wrote: On Mon, 11 Oct 2010 21:46:26 +0200, Lutger wrote: Where can I find the function to convert from c-style string to a normal D string? It used to be toString in std.string, but that one is deprecated. Thanks. import std.conv; const char* cString; string dString = to!string(cString) -Lars Oh wow, I didn't knew that would work. Awesome. I don't think it works the other way, though, you still have to use std.string.toStringz(). -Lars
Re: lvalue method
On Fri, 08 Oct 2010 09:33:22 +0200, Benjamin Thaut wrote: Hi, I'm writing a vec4 math struct and I have a method of which the return value has to be a lvalue so I wonder which is the correct way to do this: vec4 Normalize() const { ... } //won't work, not a lvalue ref vec4 Normalize() const { vec4 temp; ... return temp; } //will this lead to a segfault or not? The compiler shouldn't even accept this. When I try a similar thing, DMD says Error: escaping reference to local variable temp. ref vec4 Normalize() const { vec4* temp = new vec4; ... return *temp; } //ugly, don't want to allocate anything on the heap This would work, since the variable is no longer on the stack and thus survives the return of the function. auto ref vec4 Normalize() const { vec4 temp; ... return temp; } //will this lead to a segfault? Well, that should compile, but it doesn't work the way you want. 'auto ref' means that the function returns by ref if the return expression is an lvalue *and it would not be a reference to a local or a parameter*. So for this example, your function would return by value, not by ref. Or do I need to do it totaly in some other way? Yes, you do. :) You are trying to create a variable on the stack, and return it by reference. The problem is that when the function returns, its stack frame (the memory occupied by the function's local variables) is released. At that point the variable doesn't exist anymore, and any reference to it would be invalid. -Lars
Re: Stop function parameters from being copied.
On Thu, 07 Oct 2010 14:43:25 +, Benjamin Thaut wrote: If I want to tell the compiler that a certain function argument should not be copied (say a large struct, or a array) which is the right way to do? arrays: 1. function foo(in float[] bar) { ... } 2. function foo(ref const(float[]) bar) { ... } 3. something else Just to complement what Steven and Simen have already said, I always find it useful to think of arrays as structs. For instance, int[] is equivalent to struct IntArray { size_t length; int* ptr; } where ptr contains the memory location of the array data. (In fact, the above is not only a conceptual equivalence. The struct above is exactly, bit for bit, how a D array is implemented.) Fixed-size arrays (aka. static arrays), on the other hand, are value types, so there the equivalence goes something like // int[3] struct IntArray3 { int element0; int element1; int element2; } Therefore, if you want to pass large fixed-size arrays to a function, you'd better use 'ref' like you would with large structs. -Lars
Re: Destruction Sequence: module and classes defined within
On Tue, 05 Oct 2010 23:25:36 +0200, vano wrote: The code below: module used; import std.stdio; class ClassA { this() { writeln(A ctor); } ~this() { writeln(A dtor); } } static this() { writeln(used.sctor); } static ~this() { writeln(used.sdtor); } void main() { auto a = new ClassA(); } produces the following output (DMD v2.049): used.sctor A ctor used.sdtor A dtor The question is: should the module be allowed to be unloaded before all module-level objects/structures are destructed/unloaded? I'm no expert on this, but I think it has to be that way. Consider this: class Foo { ... } Foo foo; static this() { foo = new Foo; } static ~this() { foo.doStuff(); } So you see, if foo had already been destroyed and garbage collected, my program would have crashed when the module static destructor was run. Thus, I guess, running the garbage collector for the final time has to be one of the last things done on program shutdown, after running all module destructors. -Lars
Initialisation of static immutable arrays
I have a program that uses an immutable array, the contents of which are known at compile time. Thus, ideally, I want it to be placed in the .rodata segment of the program. Firstly, I seem to remember reading that using an array literal in D will always result in a heap allocation. Is this correct? Secondly, if the above is not true, how can I verify that the array in the following piece of code isn't allocated and/or copied anew every time the program runs, or even worse, every time foo() is called? void foo() { static immutable int[3] = [1, 2, 3]; } I know, RTFAsm, but some help with that would be appreciated. ;) Thirdly, intuition tells me that when the array is immutable, the 'static' shouldn't have an effect. But experiments (i.e. printing the adress of the array) indicate that it does. Is there some reason for this, or is it just a shortcoming of the compiler? -Lars
Re: Initialisation of static immutable arrays
On Wed, 06 Oct 2010 10:16:45 +, Lars T. Kyllingstad wrote: static immutable int[3] = [1, 2, 3]; ..should of course be static immutable int[3] a = [1, 2, 3]; -Lars
Re: Initialisation of static immutable arrays
On Wed, 06 Oct 2010 07:39:48 -0400, Steven Schveighoffer wrote: On Wed, 06 Oct 2010 06:16:45 -0400, Lars T. Kyllingstad pub...@kyllingen.nospamnet wrote: [...] Secondly, if the above is not true, how can I verify that the array in the following piece of code isn't allocated and/or copied anew every time the program runs, or even worse, every time foo() is called? void foo() { static immutable int[3] = [1, 2, 3]; } Actually, static probably will prevent it from being created every time foo is called. I don't think there's a way to prevent it from being created every time the program is run. Does anyone know a way to verify this? (If it is in fact created every time the function runs, I'll change it to a module-level array initialised in a 'static this()' instead.) I know, RTFAsm, but some help with that would be appreciated. ;) Thirdly, intuition tells me that when the array is immutable, the 'static' shouldn't have an effect. But experiments (i.e. printing the adress of the array) indicate that it does. Is there some reason for this, or is it just a shortcoming of the compiler? Of course. If you realize that the expression [1,2,3] is not immutable, then it makes sense. Another example to help you think about it: void foo(int x) { immutable int[3] = [1,2,x]; } This must be run on every call of foo, because x can vary. I don't think that is a very good reason. The compiler could detect the special (and, might I add, common) case where an array literal whose contents are known at compile time is assigned to an immutable variable, and treat it as immutable even though [1,2,3] is formally of type int[]. BTW, I'm all for making array literals immutable. You can always make runtime-allocated arrays via a library function. I completely agree. -Lars
Re: Associative arrays give compile error
On Tue, 05 Oct 2010 12:50:44 +0100, Bob Cowdery wrote: On 05/10/2010 12:40, Bob Cowdery wrote: On 05/10/2010 12:13, Denis Koroskin wrote: On Tue, 05 Oct 2010 15:08:39 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 12:04, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:57:22 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: On 05/10/2010 11:45, Denis Koroskin wrote: On Tue, 05 Oct 2010 14:23:47 +0400, Bob Cowdery b...@bobcowdery.plus.com wrote: I can't seem to get any sense out of associative arrays. Even the simplest definition won't compile so I must be doing something daft. int[string] aa = [hello:42]; Error: non-constant expression [hello:42] What exactly is not constant about this. The example is straight out the book. Using D 2.0. bob What exactly compiler version are you using (run dmd with no args)? Works perfectly fine here (dmd2.049). It says 2.049. How odd. I've got a fair amount of code and everything else compiles fine. Can you please post complete code snippet that fails to compile? Here is the code I used to test: module aa; import std.stdio; void main() { int[string] aa = [hello:42]; writeln(aa[hello]); } # dmd -run aa.d Ah! It's some other code below it that is not giving an error but causing the error above. So the compiler is getting confused. What I was actually trying to do was create an associative array with a string as a key and a Tuple as the value. Now auto aa = [ some string: (100.0, 6100.0) ] compiles but is clearly wrong and gives rise to other errors. Does anyone know the correct way to define this and then access the tuple. import std.stdio; import std.typecons; void main() { auto aa = [hello: tuple(100.0, 6100.0)]; auto result = aa[hello]; writeln(result.field[0], , result._1); // primary and alternative way } Thanks. I've established that works for me and also that the actual array I'm using also works in the test program but it won't compile in the real program. I've commented everything else out of the file and just left... import std.typecons; auto A_RX_FILT = [ 6K0: tuple(100.0, 6100.0), 2K4: tuple(300.0, 2700.0), 2K1: tuple(300.0, 2400.0), 1K0: tuple(300.0, 1300.0), 500: tuple(500.0, 1000.0), 250: tuple(600.0, 850.0), 100: tuple(700.0, 800.0) ]; I get an error on every line: Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(100,6100) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2700) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,2400) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(300,1300) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(500,1000) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(600,850) at compile time| Definitions\dspDefs.d|51|Error: cannot evaluate tuple(700,800) at compile time| ||=== Build finished: 14 errors, 0 warnings ===| This is a bit worrying now. I moved the array into the file that uses it but I still get the same errors. Any ideas? Oh dear, this is getting worse and worse. I've still got problems with a simple definition. If I take out the one with the tuple and leave in this one: enum E_MODE { LSB,// 0 USB,// 1 DSB,// 2 CWL,// 3 CWU,// 4 FMN,// 5 AM,// 6 DIGU,// 7 SPEC,// 8 DIGL,// 9 SAM,// 10 DRM// 11 } // Associative array for translation auto A_MODE = [ LSB: E_MODE.LSB, USB: E_MODE.USB, DSB: E_MODE.DSB, CWL: E_MODE.CWL, CWU: E_MODE.CWU, FMN: E_MODE.FMN, AM: E_MODE.AM, DIGU: E_MODE.DIGU, SPEC: E_MODE.SPEC, DIGL: E_MODE.DIGL, SAM: E_MODE.SAM, DRM: E_MODE.DRM ]; I get: Definitions\dspDefs.d|25|Error: non-constant expression [LSB:cast(E_MODE)0,USB:cast(E_MODE)1,DSB:cast(E_MODE)2,CWL:cast (E_MODE)3,CWU:cast(E_MODE)4,FMN:cast(E_MODE)5,AM:cast(E_MODE) 6,DIGU:cast(E_MODE)7,SPEC:cast(E_MODE)8,DIGL:cast(E_MODE) 9,SAM:cast(E_MODE)10,DRM:cast(E_MODE)11]| ||=== Build finished: 1 errors, 0 warnings ===| Something is seriously broken here. No, nothing is
Re: Segmentation fault on closing file in destructor
On Sun, 26 Sep 2010 20:55:33 +0200, Tom Kazimiers wrote: If I would use std.stdio.File, what would be different? Well, for one thing you won't have to write your code all over again when std.stream is deprecated, which will happen soon. std.stdio.File is really what you should use for file I/O in new code. That said, there's a chance it does exactly what you want. You don't have to open a file on construction, there's an open() function which opens a file and assigns it to the File handle. Nor do you have to worry about closing the file in the destructor, as it is automatically closed the moment the last reference to it goes out of scope. Here are a few examples of how to use it: File file;// File's a struct, so no need to use 'new' // Read a text file line by line file.open(foo.txt); foreach (line; file.byLine()) writeln(line); // Read a binary file in 4MB chunks file.open(foo.dat); foreach (ubyte[] chunk; file.byChunk(4*1024)) doStuffWith(chunk); // Read up to 100 ints from a file file.open(myInts); auto buffer = new int[100]; auto data = file.rawRead(buffer); -Lars
Re: Where is module dstats.all for dflplot?
On Sat, 18 Sep 2010 07:15:35 -0400, Sam Hu wrote: Greetings! I want to have a try on dflplot.But I don't find module dstats.all which is used by dflplot.d,could anybody let me where it is? Thank you. Hi! David Simcha (the dflplot author) has changed the name of the library to Plot2Kill, so if you're still using dflplot, it's an old version. Check out the Plot2Kill project for the latest version: http://www.dsource.org/projects/plot2kill As far as I know, dstats is not required to use Plot2Kill, it's only used for the demo/test application. Anyway, if you need it, you can find it here: http://www.dsource.org/projects/dstats -Lars
Re: How to avoid the console from apearing.
On Wed, 18 Aug 2010 13:50:34 -0400, Nick Sabalausky wrote: Steven Schveighoffer schvei...@yahoo.com wrote in message news:op.vhl46mdneav...@localhost.localdomain... Changes are afoot to std.process, we recently got a blocker fixed (not yet in svn, but someone submitted a correct patch) Issue #? 3979
Re: rdmd only works with files in current directory on Windows?
On Sat, 14 Aug 2010 14:58:05 +0200, simendsjo wrote: c:\temp\src\test.d c:\temprdmd src\test The system cannot find the path specified. c:\temprdmd src/test std.file.FileException: (...)\.rdmd\rdmd-src/test.d-(...): The system cannot find the path specified. Using rdmd 20090902, dmd 2.048 and 64 bit win7 It doesn't work on Linux either, you have to be in the same directory as the source file. But I'm not sure it was ever supposed to work, i.e. Andrei didn't account for that use when he wrote it. If you really want this to work, you could submit an enhancement request to bugzilla. -Lars
Re: std.string.chomp error
On Mon, 09 Aug 2010 17:35:56 -0700, Jonathan M Davis wrote: On Monday, August 09, 2010 17:09:03 simendsjo wrote: On 10.08.2010 02:09, Jonathan M Davis wrote: On Monday, August 09, 2010 16:59:07 bearophile wrote: simendsjo: Ahem.. :) Yes, I did miss your answer! How I got fooled by the preview pane and never noticed the scrollbar. No problem, it happens, don't worry. I cannot see how your other bug report relates to this though. My other bug report is about this line in your code: if (delimiter == null) I don't like it :-) Bye, bearophile Why, because it should be if(delimiter is null) or just if(!delimiter) - Jonathan M Davis Hehe.. You're a bit beyond my D level right now. At least I now know null == false and you can do reference is null :) IIRC, you're not really supposed to do delim == null but rather us delim is null or shorten to to just !delim. Why, I don't recall off the top of my head, but it might be because delim == null would be calling Object.opEquals(), and there's no need for that function call (though fortunately delim == null translates to Object.opEquals(delim, null) rather than delim.opEquals(null) which avoids issues where the lhs is null and causes it to go boom). In either case, for null checks, I'd suggest either just using the reference by itself or to explictly use is null if you want the extra clarity. No, using 'is' won't work. Check this out: int[] a; assert (a == null); assert (a is null); a = new int[10]; a.length = 0; assert (a == null); assert (a !is null); The thing is, '==' tests whether two arrays are equal, that is, that they are equally long and that their elements are equal. Any empty array is equal to null -- in fact, in this context 'null' is just a way of denoting an empty array that doesn't point to any particular memory block (i.e. hasn't been initialised yet). // This is what '==' does bool mimicEquals(int[] a, int[] b) { if (a.length != b.length) return false; foreach (i; 0 .. a.length) if (a[i] != b[i]) return false; return true; } 'is', on the other hand, tests whether two arrays are identical, i.e. that they have the same length and *refer to the same piece of memory*. // This is (sort of) what 'is' does bool mimicIs(int[] a, int[] b) { return (a.ptr == b.ptra.length == b.length); } -Lars
Re: std.string.chomp error
On Tue, 10 Aug 2010 01:48:17 -0700, Jonathan M Davis wrote: On Tuesday 10 August 2010 00:30:37 Lars T. Kyllingstad wrote: No, using 'is' won't work. Check this out: int[] a; assert (a == null); assert (a is null); a = new int[10]; a.length = 0; assert (a == null); assert (a !is null); The thing is, '==' tests whether two arrays are equal, that is, that they are equally long and that their elements are equal. Any empty array is equal to null -- in fact, in this context 'null' is just a way of denoting an empty array that doesn't point to any particular memory block (i.e. hasn't been initialised yet). // This is what '==' does bool mimicEquals(int[] a, int[] b) { if (a.length != b.length) return false; foreach (i; 0 .. a.length) if (a[i] != b[i]) return false; return true; } 'is', on the other hand, tests whether two arrays are identical, i.e. that they have the same length and *refer to the same piece of memory*. // This is (sort of) what 'is' does bool mimicIs(int[] a, int[] b) { return (a.ptr == b.ptra.length == b.length); } -Lars Actually, it looks to me that that's an argument for using is for checking for null rather than ==, since == isn't really going to tell you. The fact that == doesn't care about whether an array is null makes it not work for checking for whether an array is null. I guess it depends on what behaviour you're after. In the present case, if you want chomp(a, null) and chomp(a, ) to do the same thing, then you should use '=='. If you want chomp(a, ) to simply do nothing, use 'is'. I just figured that the former was the desired behaviour here. If it isn't, I agree with you. :) 1. As I understand it, using is instead of == is for all references, not just arrays and their bizarre pseudo-null state. Using is with a class will avoid calling opEquals() and does exactly what you want when checking whether a class reference is null. Fun fact: Actually, 'is' works for any type. assert (1 is 1); As I've understood it, 'a is b' is true if the variables a and b contain the exact same bits. If a and b are value types, this must mean they have the same value, and if they are references (including arrays), it means they refer to the same data. 2. For arrays, if you want to check whether it really is null, then you _must_ use is, because == obviously isn't going to tell you. It'll just lump empty arrays in with null ones. For instance, if you want to check that an array has never been initialized or that it has been set to null and never set to something else, then you need to use is. 3. On the other hand, if what you really care about is checking whether an array has any elements and you don't care about whether it's null or not, then the empty function/property would be the better way to go. It's quite explicit, and it's more generic, doing things the way that ranges are done. I totally agree with you. Lately, I have started using empty (as well as the other range primitives) for arrays myself. I just disagreed that 'is' would produce what I perceived to be the right behaviour for the function in question. But that perception may well be wrong. ;) Personally, I think that the way that null is handled with arrays and associative arrays is a poor design choice (if they're null, they should be null until you assign to them with new rather than this whole null but not null nonsense), but we're stuck with it I guess. There, I don't agree with you. Arrays are a sort of pseudo-reference type, so I don't mind 'null' being a sort of pseudo-null in that context. Actually, I find it to be quite elegant. It's a matter of taste, I guess. -Lars
Re: std.string.chomp error
On Tue, 10 Aug 2010 07:50:34 -0400, bearophile wrote: Lars T. Kyllingstad: There, I don't agree with you. Arrays are a sort of pseudo-reference type, so I don't mind 'null' being a sort of pseudo-null in that context. Actually, I find it to be quite elegant. It's a matter of taste, I guess. I suggest you to write down the things you don't like and the design you desire here. ?? I like how it is designed now, that was my point. -Lars
Re: Problem with std.array(std.regex.splitter())
On Mon, 09 Aug 2010 07:31:21 -0400, bearophile wrote: Jonathan M Davis: Well, the requirement for save() being part of a forward range is fairly recent, and a bunch of ranges which are supposed to be forward ranges don't have them even though they're supposed to. The change was made fairly close to the release of 2.047, I believe, and it was missed for many ranges. It's mostly if not entirely fixed in svn. Actually, if I try and compile Bearophile's code on my machine (which has a fairly recent version of phobos), it compiles just fine. I have tried the latest beta and indeed it works, thank you. Where can I find information about the purposes and meaning of save()? TDPL? It should be in the documentation of std.range.isForwardRange(), but Andrei seems to have forgotten it. He did describe it in his 'On Iteration' article, though: http://www.informit.com/articles/article.aspx?p=1407357 Check out page 7, section 'Forward Ranges'. (I think the whole article is worth reading, if you haven't already -- it really helped me understand ranges.) -Lars
Re: Casting away const
On Mon, 09 Aug 2010 10:35:02 -0400, Steven Schveighoffer wrote: On Mon, 09 Aug 2010 10:27:09 -0400, Don nos...@nospam.com wrote: Steven Schveighoffer wrote: On Mon, 09 Aug 2010 09:57:47 -0400, bearophile bearophileh...@lycos.com wrote: Steven Schveighoffer: I thought it was you're on your own, not undefined behavior. The former implies there is some right way to do this if you know more about the data than the compiler, the latter implies that there is no right way to cast away const. Am I wrong? In my opinion if this thing is well designed then you go in undefined behaviour only when you change the contents of something after you have removed its const nature with a cast. Just casting const away and then reading the data can't be undefined behaviour, otherwise casting const away is useless and can be totally disallowed. Casting away const just to read the data is useless. You can read const data without a cast. No you can't. You can't pass it to a C function. Sure you can. extern(C) int strlen(const(char) *arg); But my understanding is that casting away const to write should be doable if you know what you're doing. If this is undefined behavior, then that's fine, I'm just unclear on what undefined behavior actually means. I thought undefined behavior means that you cannot count on the behavior to work in the future. An example of where casting away const to write should be allowed is for a hypothetical mutable member: class C { private Mutable!(int) cache = -1; int expensiveFunction() const { return cache == -1 ? cache = _expensiveFunctionImpl() : cache; } private int _expensiveFunctionImpl() const {...} } If this is undefined, then something like this cannot be relied on, even when performance is critical. -Steve I really can't see how the compiler could make that work, without destroying most of the benefits of const. For example, if that code is legal, it disallows most const-related optimisation. Why not? What possible optimization can the compiler do here? Mutable has an assign operation that is labeled as const, it should be callable by the compiler. I haven't really seen what const optimizations can be, so maybe an example (even if unimplemented) is helpful. The compiler does an optimization on const/immutable struct members which I reported as a bug: http://d.puremagic.com/issues/show_bug.cgi?id=3449 -Lars
Re: std.string.chomp error
On Mon, 09 Aug 2010 18:58:36 +0200, simendsjo wrote: The documentation says /*** * Returns s[] sans trailing delimiter[], if any. * If delimiter[] is null, removes trailing CR, LF, or CRLF, if any. */ To adhere to the documentation, chomp must be changed from: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (endsWith(s, delimiter)) { return s[0 .. $ - delimiter.length]; } return s; } to: C[] chomp(C, C1)(C[] s, in C1[] delimiter) { if (delimiter == null) return chomp(s); else if (endsWith(s, delimiter)) return s[0 .. $ - delimiter.length]; else return s; } Either that, or the documentation for it needs to be changed. Anyway, it would be great if you'd report this. http://d.puremagic.com/issues/ Thanks! -Lars
Re: Wanting an immutable associative array in a class
On Thu, 29 Jul 2010 22:55:35 -0400, bearophile wrote: RedZone: But it would be nice if I could have the array reference itself be immutable and not just the array's contents. Is there any way I could do this? Let's say your code is as your second example: class Foo { private: immutable int[string] bar; public: this() { bar = [AB:1, CD:2, EF:3]; } } void main() { auto f = new Foo; } How can you change the array reference outside the class constructor? But that was not his second example. :) His second example used the type immutable(int)[char[]] while you used the correct one, immutable(int[char[]]) RedZone: Even though the overall type is immutable, you can still set it in a constructor, like bearophile showed. May I also suggest a small improvement? Doing it like this means that the array will be constructed anew every time you create an instance of the class. If it's meant to be immutable, and you know all the elements of the array at compile time, that's just wasteful. In that case, it's probably better to make it a static member variable, and set its value in a static constructor. That way it will only get constructed once, at program startup. class Foo { private: static immutable int[string] bar; static this() // Only run when program loads { bar = [AB: 1, CD: 2, EF: 3]; } public: ... } -Lars
Re: exern (C) linkage problem
On Mon, 19 Jul 2010 18:01:25 -0400, bearophile wrote: typedef char* Cstring; extern(C) Cstring strcmp(Cstring s1, Cstring s2); ... You can use just a struct too: import std.string: toStringz; struct Cstring { const(char)* ptr; } extern(C) Cstring strcmp(Cstring s1, Cstring s2); Cstring toCString(T)(T[] s) { return Cstring(toStringz(s)); } void main() { auto s1 = abba; auto s2 = red; // auto r = strcmp(toCString(s1), s2); // compile error auto r = strcmp(toCString(s1), toCString(s2)); // OK } Bye, bearophile Good point. Actually, I think there should be a CString type in Phobos, but I think it should wrap a ubyte*, not a char*. The reason for this is that D's char is supposed to be a UTF-8 code unit, whereas C's char can be anything. -Lars
Re: exern (C) linkage problem
On Tue, 20 Jul 2010 05:10:47 -0400, bearophile wrote: In that code, for further safety, I'd like to make it not possible (without a cast) code like this (here toStringz doesn't get called): strcmp(Cstring(s1.ptr), Cstring(s2.ptr)); So I think this code is a bit better: import std.string: toStringz; struct Cstring { const(char)* ptr; // const(ubyte)* ? static Cstring opCall(string s) { Cstring cs; cs.ptr = toStringz(s); return cs; } } extern(C) Cstring strcmp(Cstring s1, Cstring s2); void main() { auto s1 = abba; auto s2 = red; auto r2 = strcmp(Cstring(s1), Cstring(s2)); } Lars T. Kyllingstad: but I think it should wrap a ubyte*, not a char*. The reason for this is that D's char is supposed to be a UTF-8 code unit, whereas C's char can be anything. Right. But toStringz() returns a const(char)*, so do you want to change toStringz() first? Yes. I think we should stop using char* when interfacing with C code altogether. The right thing to do, if you can call it that, would be to use char* only if you KNOW the C function expects text input encoded as UTF-8 (or just plain ASCII), and ubyte* for other encodings and non- textual data. But this rule requires knowledge of what each function does with its input and must hence be applied on a case-by-case basis, which makes automated translation of C headers to D difficult. So I say make it simple, don't assume that your C functions handle UTF-8, and use ubyte* everywhere. (Actually, it's not that simple, either. I just remembered that C's char is sometimes signed, sometimes unsigned...) Maybe this should be discussed on the main NG. It's been bothering me for a while. I think I'll start a topic on it later. -Lars
Re: Why are string literals zero-terminated?
On Tue, 20 Jul 2010 13:26:56 +, Lars T. Kyllingstad wrote: On Tue, 20 Jul 2010 14:59:18 +0200, awishformore wrote: Following this discussion on announce, I was wondering why string literals are zero-terminated. Or to re-formulate, why only string literals are zero-terminated. Why that inconsistency? What's the rationale behind it? Does anyone know? So you can pass them to C functions. Note that even though string literals are zero terminated, the actual string (the array, that is) doesn't contain the zero character. It's located at the memory position immediately following the string. string s = hello; assert (s[$-1] != '\0'); // Last character of s is 'o', not '\0' assert (s.ptr[s.length] == '\0'); Why is it only so for literals? That is because the compiler can only guarantee the zero-termination of string literals. The memory following a string in general could contain anything. string s = getStringFromSomewhere(); // I have no idea where s is coming from, so I don't // know whether it is zero-terminated or not. Better // make sure. someCFunction(toStringz(s)); -Lars
Re: exern (C) linkage problem
On Sun, 18 Jul 2010 13:08:57 -0700, Charles Hixson wrote: I'm trying to link a C routine to a D program, passing string parameters, but I keep getting segmentation errors. As you can see, these are simple test routines, so the names don't reflect current status, but merely where I intend to arrive...but I've hit severe roadblocks. (FWIW, I've tried including -fpic in the gcc command, and it didn't appear to make any difference.) Makefile: biblio: biblio.d sqlitebase.o dmd biblio.d sqlitebase.o -ofbiblio sqlitebase.o: sqlitebase.c sqlitebase.h gcc -c sqlitebase.c biblio.d: import std.stdio; //extern (C) void dbdefine (char[] str); extern (C) void dbdefine (char[] inStr, ref char[255] outStr); void main() { char[255] retVal; char[] msg = cast(char[])Hello from C\0; dbdefine (msg, retVal); writeln (Hello, World); } sqlitebase.h: //void dbdefine (char str[]); void dbdefine (char inStr[], char outStr[255]); sqlitebase.c: #include sqlitebase.h //void dbdefine (char str[]) void dbdefine (char inStr[], char outStr[255]) { //int i = 0; //while (str[i] != 0) i++; //printStr (i, str); //^^--segmentation fault--^^ // printf (%s/n, str); //^^--warning: incompatible implicit declaration of built-in function ‘printf’--^^ //int i = str[0]; //putchar(i); //^^--segmentation fault--^^ int i = -1; while (++i 255) { if (inStr[i] == 0) break; outStr[i] = inStr[i]; } } Since bearophile already answered with a solution to your problem, I'll just chime in with a few small tips (of which you may already be aware): 1. D string *literals* are already zero-terminated, so you don't need to add the \0 character explicitly. Also, they cast implicitly to const (char)*, so if your function doesn't change inStr, it's perfectly fine to do extern(C) void dbdefine (const char* inStr); dbdefine(Hello from C); 2. For D strings in general the \0 must be added, but this is very easy to forget. Therefore, when passing strings to C functions I always use the std.string.toStringz() function. It takes a D string, adds a \0 if necessary, and returns a pointer to the first character. string s = getAStringFromSomewhere(); dbdefine(toStringz(s)); -Lars
Re: Anyone know why this CTFE isn't working?
On Fri, 16 Jul 2010 11:46:48 +0200, Rory McGuire wrote: import std.stdio; struct State { string s; string getString() { return s; } static State opCall(string s) { State ret; ret.s = s; return ret; } } void main() { auto s = State(adf); pragma(msg, s.getString()); } dmd Output: (line 14 is the pragma statement) struct.d(14): Error: variable s cannot be read at compile time struct.d(14): Error: cannot evaluate s.getString() at compile time s.getString() It's not working because s isn't a compile-time quantity. Try: enum s = State(adf); -Lars
Re: Multi dimensional array question.
On Wed, 14 Jul 2010 16:57:13 -0400, Heywood Floyd wrote: Lars T. Kyllingstad Wrote: But then arrays would be different from all other types! If you have an array of 3 Ts, that is written T[3], regardless of what T is. Now consider these two cases: A. T is an int. Then T[3] becomes int[3]. B. T is an int[string]. Then T[3] becomes int[string][3]. In case A, the first element of the array is accessed like this: int[3] a; int firstA = a[0]; Since a is an array of int, firstA is of course an int. But then, since b is an array of int[string], we have int[string][3] b; int[string] firstB = b[0]; If we again want to access element foo of the associative array which is firstB, we write firstB[foo]. And so we have the following three ways to get to that element, which *must* be equivalent because that's how the language is defined: // Using firstB as an intermediate step int[string] firstB = b[0]; int x = firstB[foo]; // Drop the intermediate variable firstB int x = (b[0])[foo]; // Drop the redundant parentheses int x = b[0][foo]; So you see, it can't be any other way than the way it is. :) -Lars Thank you for the elaborate answer! When you put it like that, it does make sense. But I'm sorry. I refuse. The reason I refuse is those examples are void of any higher semantic meaning. Once we add a semantic meaning, it simply becomes backwards: int[MAX_WIDTH][MAX_HEIGHT] map2d; map2d[x][y] = 9; // Wrong! At least in my head, this is cognitive dissonance. To me, the language acts as if it's low-level semantics outweighs my high-level semantics and I should correct my thinking for that. I refuse! Seems to me it could just as well work as: int[string][3] b; int[3] firstB = b[foo]; int i = firstB[0]; int j = (b[foo])[0]; int k = b[foo][0]; But I feel like I'm the only one feeling this, so I'll just let it go and hope my dear C-style arrays stay in :) BR /HF PS. Never thought I'd find a reason to love C.. DS. I do agree that, if possible, the language should match how most people think. But in this case, it is impossible, because of templates. How would the following example work with T = int[3], if arrays worked the way you want? struct MyArray(T) { T[] a; } C doesn't have this issue, because it doesn't have templates. And I'll have my templates over C-style array declarations any time, thank you. :) -Lars
object.reserve() and array size
Is object.reserve() only useful for large arrays, or should I always use it if I intend to append to an array? Let's say I want to read some data, and I expect there to be ~100 bytes of data. Is there any point in using reserve() first, or will there always be that much memory available to an array? byte[] buffer; buffer.reserve(100); foreach(byte b; dataSource) buffer ~= b; -Lars
Re: object.reserve() and array size
On Wed, 14 Jul 2010 10:35:19 -0400, Steven Schveighoffer wrote: On Wed, 14 Jul 2010 06:01:10 -0400, Lars T. Kyllingstad pub...@kyllingen.nospamnet wrote: Is object.reserve() only useful for large arrays, or should I always use it if I intend to append to an array? Let's say I want to read some data, and I expect there to be ~100 bytes of data. Is there any point in using reserve() first, or will there always be that much memory available to an array? byte[] buffer; buffer.reserve(100); foreach(byte b; dataSource) buffer ~= b; Yes, you should always reserve if you know how much data is coming. If you do not here is what happens: Upon adding the first byte, a block of 16 bytes is allocated Upon adding the 16th byte (there is one byte for padding), a *new* block of 32 bytes is allocated, and the 15 previous bytes are copied to the 32-byte block. The original 16 byte block is left allocated because there could be other aliases to the data. Upon adding the 32nd byte, a block of 64 bytes is allocated, rinse and repeat. Upon adding the 64th byte, a block of 128 bytes is allocated, same deal. Then the block will hold 100 bytes. If you reserve 100 bytes, then a block of 128 bytes is allocated, and your data all goes in there. OT, I assume you realize that reading data in this way is horribly inefficient :) You should read a block at once if possible. Yeah, that was just an artificial example. :) The actual use case was building a string from substrings. Thanks! -Lars
Re: Multi dimensional array question.
On Mon, 12 Jul 2010 17:23:16 -0400, Heywood Floyd wrote: bearophile Wrote: Heywood Floyd: This had me crazy. I ended up putting the brackets on the variable, like int marr[3][5]; then it worked like marr[2][4] = 9; That's present only for compatibility with C syntax, this means that you can use it to perform a quicker port of C code to D, but you are supposed to later convert it to D-style array definitions. See also: http://www.digitalmars.com/webnews/newsgroups.php? art_group=digitalmars.Darticle_id=113185 Bye, bearophile Aha, good to know! Thanks! (So this might go away in the future? Or require a -cstyle compile flag?) *** I have a feeling this backwards-array stuff is gonna be one of the things my brain will repel for as long as it can. To me, it seems equal to saying you declare a function like: void foo(string name, int age){ //... } And then call it by doing foo(90,Benny) and this makes sense because the arguments are actually pushed on the stack in reverse at runtime, so they arrive in the correct order in the function. And this is especially important with tuples. or something. Ok, I understand this has some deep purpose that I still don't understand, I'm just, yeah. *tear* (Although this is way out of my league: For instance, if a T is an int[3][4], then why can't T[string] be a int[string][3][4], and be accessed with arr[a][2][3]? Seems just like a matter of taste?) But then arrays would be different from all other types! If you have an array of 3 Ts, that is written T[3], regardless of what T is. Now consider these two cases: A. T is an int. Then T[3] becomes int[3]. B. T is an int[string]. Then T[3] becomes int[string][3]. In case A, the first element of the array is accessed like this: int[3] a; int firstA = a[0]; Since a is an array of int, firstA is of course an int. But then, since b is an array of int[string], we have int[string][3] b; int[string] firstB = b[0]; If we again want to access element foo of the associative array which is firstB, we write firstB[foo]. And so we have the following three ways to get to that element, which *must* be equivalent because that's how the language is defined: // Using firstB as an intermediate step int[string] firstB = b[0]; int x = firstB[foo]; // Drop the intermediate variable firstB int x = (b[0])[foo]; // Drop the redundant parentheses int x = b[0][foo]; So you see, it can't be any other way than the way it is. :) -Lars
Re: Recommended way to do RAII cleanly
On Sun, 11 Jul 2010 23:25:32 -0700, Jonathan M Davis wrote: Okay. There are cases where you want a constructor to do something when the class/struct is created, and you want the destructor to do something when the class/struct goes out of scope. A classic example would be an autolock for a mutex. Another would be the hourglass in MFC - it's displayed when the object is created and disappears when the object is destroyed (so all you have to do is declare the object it at the beggining of the function and it automatically is displayed and then disappears). This is classic RAII. Obviously, because classes are reference types with infinite lifetime while structs are value types with their lifetime restricted to their scope, structs would be the better choice for RAII. I have noticed a bit of a snag however: structs can't have default constructors. After reading TDPL, I completely understand that structs can't have default constructors due to how the init property works. However, the classic case where you want to simply declare an object and have it do what it does through RAII then falls apart. Ideally, you'd have something like this struct S { this() { /* do something */ } ~this() { /* undo what you did before or do whatever clean up is required for it */ } } void main() { auto s = S(); /* whatever the rest of main() does */ } Thanks to the lack of default constructor, you can't do that. Therefore, I see 2 options: 1. Create a nonsensical constructor that takes an argument of _some_ kind which is totally ignored. 2. Create a factory function to create the struct, and it does whatever would have been in the default constructor. Out of those two options, the second seems the best, but it seems to me that there have got to be more options than that. So, the question is what would be the best option (be it one of those or another that I haven't though of) to do RAII in the general case? What would be best practice for D when dealing with structs intended for RAII without any arguments to their constructor when you can't have a default constructor? I'd say option 2 is your best bet. I don't know any other way to fake default construction. That said, the recommended best practice for D is, if possible, to use scope guards: void doStuffWith(string resourceName) { auto resource = acquire(resourceName); scope(exit) release(resource); ... // Do stuff with resource here } -Lars
Re: core.sys.posix.grp missing
On Mon, 21 Jun 2010 14:07:19 -0400, Chick Corea wrote: Using dmd v2.0.47, the following code: import core.sys.posix.pwd; import core.sys.posix.grp; yields the following error message: Error: module grp is in file 'core/sys/posix/grp.d' which cannot be read Checking the src/druntime/import directories, I find that a POSIX pwd module is present: src/druntime/import/core/sys/posix/pwd.d src/druntime/import/core/sys/posix/pwd.di But a POSIX grp module is absent. Neither is there any code related to POSIX grp functions in any of the modules. When I found the pwd.d file, I forgot to check for a grp.d file, guessing that if one was present then so was the other. So - am I missing something ? Or do I need to write one myself ? CHICKZ Unfortunately, there are still some POSIX headers missing from druntime. It would be great if you file a bug on this, so it isn't forgotten: http://d.puremagic.com/issues/ If you end up writing it yourself, I'm sure Sean will be happy if you attach it to the bug report. :) -Lars
Re: setMaxMailboxSize
On Thu, 17 Jun 2010 21:31:10 +, Byron Heads wrote: is setMaxMailboxSize not implemented yet or is it bugged? It seems it got implemented today. :) http://www.dsource.org/projects/phobos/changeset/1662 You can use the SVN version of Phobos, or wait for the next release. -Lars
Re: Proper way to access posix functions
On Thu, 17 Jun 2010 20:09:29 +, Byron Heads wrote: Whats the proper way to get access to some of the Posix functions? ie. fork setsid... import core.sys.posix.unistd; //? Is it proper to import from core.sys Yes, that is correct. :) -Lars
Re: D Programming Language
On Tue, 08 Jun 2010 11:23:23 +0100, Patrick Byrne wrote: Amazon (UK) tells me that publication of this book is delayed. Is it still coming soon, please? I also ordered it from Amazon UK, and got the same message. But the book is, as far as I know, finished and printed. So I suppose it's mostly a matter of transportation time. :) -Lars
Re: Tuple to tuple conversion
On Tue, 08 Jun 2010 12:39:43 +0200, Simen kjaeraas wrote: Simen kjaeraas simen.kja...@gmail.com wrote: Lars T. Kyllingstad pub...@kyllingen.nospamnet wrote: FWIW, I've run across the same error, while writing code that had nothing to do with tuples. And I've seen others complaining about it too. It seems to be a rather elusive bug in Phobos. This has now been tracked down to the importing of std.typecons in two included files. Test case: // module a; import std.typecons; alias Tuple!( float ) foo; // module b; import std.typecons; Forgot to mention, this only happens with -unittest. http://d.puremagic.com/issues/show_bug.cgi?id=4294 That's consistent with my experiences too. It seems to be triggered by a Phobos unittest. Still, I can't reproduce it with your test case. Which DMD version are you using? -Lars
Re: Tuple to tuple conversion
On Tue, 08 Jun 2010 12:56:04 +0200, Simen kjaeraas wrote: Lars T. Kyllingstad pub...@kyllingen.nospamnet wrote: That's consistent with my experiences too. It seems to be triggered by a Phobos unittest. Still, I can't reproduce it with your test case. Which DMD version are you using? 2.045. Actually, I can't reproduce it now either. Ah, found the problem. dmd a b -unittest works. dmd b a -unittest does not. Ok, now I can reproduce it too, with 2.046. This just makes it even more clear that it is a DMD bug, not a Phobos one. I've been running into a lot of these order-of-compilation bugs lately. :( -Lars
Re: D Programming Language
On Tue, 08 Jun 2010 13:00:51 +0100, Robert Clipsham wrote: On 08/06/10 11:23, Patrick Byrne wrote: Amazon (UK) tells me that publication of this book is delayed. Is it still coming soon, please? -- Patrick Byrne I ordered it from amazon.com, it was half the priceof the UK version ;) I don't know when you ordered it, but that has changed now, at least. At amazon.co.uk it costs £18.50, while at amazon.com it sells for $42.70 -- roughly £29. Also, for Europeans, the delivery cost is lower if you order from UK. -Lars
What does 'scope' mean for non-class types?
In D2, what is the effect (if any) of 'scope' in the following situations? scope int a; struct B { ... } scope B b; scope int[] c; // According to the spec, 'in' is shorthand for 'const scope'. void foo(in char[] d) { ... } Thanks, -Lars
Re: Loop optimization
On Fri, 14 May 2010 02:38:40 +, kai wrote: Hello, I was evaluating using D for some numerical stuff. However I was surprised to find that looping array indexing was not very speedy compared to alternatives (gcc et al). I was using the DMD2 compiler on mac and windows, with -O -release. Here is a boiled down test case: void main (string[] args) { double [] foo = new double [cast(int)1e6]; for (int i=0;i1e3;i++) { for (int j=0;j1e6-1;j++) { foo[j]=foo[j]+foo[j+1]; } } } Any ideas? Am I somehow not hitting a vital compiler optimization? Thanks for your help. Two suggestions: 1. Have you tried the -noboundscheck compiler switch? Unlike C, D checks that you do not try to read/write beyond the end of an array, but you can turn those checks off with said switch. 2. Can you use vector operations? If the example you gave is representative of your specific problem, then you can't because you are adding overlapping parts of the array. But if you are doing operations on separate arrays, then array operations will be *much* faster. http://www.digitalmars.com/d/2.0/arrays.html#array-operations As an example, compare the run time of the following code with the example you gave: void main () { double[] foo = new double [cast(int)1e6]; double[] slice1 = foo[0 .. 999_998]; double[] slice2 = foo[1 .. 999_999]; for (int i=0;i1e3;i++) { // BAD, BAD, BAD. DON'T DO THIS even though // it's pretty awesome: slice1[] += slice2[]; } } Note that this is very bad code, since slice1 and slice2 are overlapping arrays, and there is no guarantee as to which order the array elements are computed -- it may even occur in parallel. It was just an example of the speed gains you may expect from designing your code with array operations in mind. -Lars