Re: Why doesn't this have a length?
On 2012-03-13 14:24:37 +, H. S. Teoh said: Indeed. Would've thought const AA keys would be reasonable. (In Python they're *required*... :) [...] I'm of the opinion that AA keys should be *implicitly* immutable. Seconded, whole-heartedly. -- Magnus Lie Hetland http://hetland.org
Re: Sorting char arrays
On 2012-03-12 17:33:35 +, Ali Çehreli said: You can use isNarrowString to either disallow or provide special implementation for narrow strings (char[] and wchar[]): Ah -- useful, thanks! -- Magnus Lie Hetland http://hetland.org
Re: Sorting char arrays
On 2012-03-12 17:24:56 +, Jonathan M Davis said: The problem is that sort requires a random access range, and narrow string (string and wstring) aren't, because they're variable length encoded. I'm not sure that strings _can_ be efficiently sorted, because of that, but maybe there's a sorting algorthm that could do it reasonably efficiently, I'd certainly think that'd be posible. (Might, in fact, be a nice problem for the students in my algorithms class ;) I guess I'm just tripped up by the fact that char[] is treated as an "almost-string", and hence is "infected" by the variable-length encoding of string (i.e., const char[]). This all makes sense, for sure -- at least as a practical tradeoff or the like. (After all, UTF-8 is a super-elegant solution to a very difficult problem.) It's just so easy to assume that T[] is a random-access range. It seems so *obvious*. And it is true for any type T except the variable-length chars... :) In my case, I was just using char literals (and strings) as an easy way of encoding test cases for a template class, and the sorting (+ uniq) was just a way of removing duplicates. (Could've used a hash, of course.) So I was really just treating it as a ubyte[]. Slightly Evil[tm], I guess. and we could special case sort for narrow strings to use that one, but it's a while since I messed with sorting algorithms, so I don't remember all of their characteristics off of the top of my head. Certainly, with how sort is currenly implemented, it can't handle any range which isn't a random access range. No, I get that. I was just assuming that any T[] could be treated as a random access range if I really wanted to ;) -- Magnus Lie Hetland http://hetland.org
Re: Why doesn't this have a length?
On 2012-03-13 02:27:46 +, Simen Kjærås said: Weird. Indeed. Would've thought const AA keys would be reasonable. (In Python they're *required*... :) You get a different error message from what I get. My reduced code: [snip] http://d.puremagic.com/issues/show_bug.cgi?id=7695 I guess this issue then covers both (despite the different error messages)? I'll just leave this alone (i.e., not submit any additional tickets), then (and cast away the constness for now; seems to help). -- Magnus Lie Hetland http://hetland.org
Why doesn't this have a length?
In a template class (with State and Input as template parameters), I have the following (private) member: State[][Tuple!(const(State), const(Input))] transitions; It works well enough, but for some reason I can't access its length attribute...? (If I define other simpler, similar private attributes, such as uint[uint], I can access their length in the same location where transition.length fails.) I get an error message that seems to indicate that DMD is looking for a global identifier. I've tried instantiating with different types, e.g., uint. Am I doing something illegal?-) -- Magnus Lie Hetland http://hetland.org
Re: Sorting char arrays
On 2012-03-12 13:56:15 +, bearophile said: It's not a bug, char is meant to be a UTF-8. Right. Two workarounds: Thanks. I'm doing the sorting in a template, so this won't work -- but I guess I just can't use char as a type parameter to my template either, then :) -- Magnus Lie Hetland http://hetland.org
Re: Sorting char arrays
On 2012-03-12 13:09:18 +, Dmitry Olshansky said: Mm it should perform sort on UTF-8 buffer? Humm -- dunno ;) The UTF-8-semantics of single characters sort of slipped my mind :) Tricky thing but worths an enhancement request. I'm just thinking an array of anything that can be compared should probably be sort-able. But comparing individual UTF-8-bytes can be weird, indeed. So, yeah. I guess the weirdness follows from the fact that individual characters are considered UTF-8 :) If it's ASCII then try: sort(a.representation) representation is in std.string IRC. The thing is, I'm using sort() in a template, and I just happen to use char as the template parameter in a unit test. And since I have no special UTF-8 values in there, my own sort() works just fine. (Although maybe it shouldn't? ;) -- Magnus Lie Hetland http://hetland.org
Re: Tempfiles in unittests
On 2012-03-11 21:14:59 +, Jonathan M Davis said: So, as far as Phobos' unit tests are concerned, there's not really any need for what you're trying to do. Sure. Just would have thought that maybe some unit-testing D user out there had written a function that wrote something to a file ;-) But no problem -- not many lines to add to my own code. -- Magnus Lie Hetland http://hetland.org
Sorting char arrays
The following fails, which I guess is a bug? import std.algorithm; void main() { char[] a = ['a', 'b', 'c']; sort(a); } I thought maybe I'd report it -- sort of surprises me that it hasn't been reported before, but I couldn't find it (although I found some similar reports) in the Bugzilla. (No biggie for me, though; the Phobos sort seems to fail with all kinds of things, so I have my own anyway... ;) -- Magnus Lie Hetland http://hetland.org
Re: Tempfiles in unittests
On 2012-03-10 17:10:52 +, Jonathan M Davis said: Otherwise, this wouldn't have been a problem :) Then you'll probably have to write a wrapper function which just uses byLine and join to grab the string line by line and then put it back together again. Indeed. Not a problem. Just surprised me that there wasn't a standard way of writing file-related unit tests :) -- Magnus Lie Hetland http://hetland.org
Re: Tempfiles in unittests
On 2012-03-09 18:42:01 +, Jonathan M Davis said: File has a name property. You can do something like auto file = File.tmpfile(); auto filename = file.name; auto str = readText(filename); Yeah -- again, sorry my original post was so verbose, but part of the "problem spec" was that my tempfiles don't seem to have names (i.e., they are unnamed tempfiles, and file.name is null; platform-dependent, I think). Otherwise, this wouldn't have been a problem :) -- Magnus Lie Hetland http://hetland.org
Re: Tempfiles in unittests
On 2012-03-09 15:08:42 +, bearophile said: Magnus Lie Hetland: It seems that File has no method for reading the entire file contents into a string, so I'd have to read and concatenate lines or chunks or something? There are std.file.read() and std.file.readText(). Yeah, I found those. I guess my post was a bit verbose, but the main point was that I have a File object, but no file name (because I'm using std.stdio.tmpfile() in a unit test), so std.file.read() and std.file.readText() are useless to me... :) But I agree that std.stdio.File should have a readAll() method :-) If you think this is a good idea, add it to Bugzilla. Sure. For now, though: What's The Way[TM] to write unit tests for code that writes to files? Use tmpfile and read/concatenate the file contents myself? Something else that's more practical? (I would have thought this kind of test would be common?-) -- Magnus Lie Hetland http://hetland.org
Tempfiles in unittests
I'm testing a class that writes various things to a file, and I'd like to test that behavior, and I'm wondering what the standard solution here is. In Python, I'd just use a StringIO class, for example. It seems sort of impractical to make std.outbuffer to work as a File (even if the file-like parameter is a template parameter, the outbuffer methods don't work like the File methods, as far as I can see), so I've concluded that using std.stdio.tmpfile is the way to go. However, when I'm done with the tempfile, I'd like to have its contents as a string. It seems that File has no method for reading the entire file contents into a string, so I'd have to read and concatenate lines or chunks or something? Now, if the File returned by tmpfile had a name, I could use std.file.readText(). But no such luck (as far as I can see, tmpfile().name is null). So I'm just wondering -- what's "the way" to do this sort of testing? And if it is along the lines of what I'm doing, is there some function/method for reading the contents of a File as a string? (I guess this goes for much file-related functionality; much of it seems to be very related to file-names and actual files, rather than "file-like" objects, i.e., those with the appropriate methods...) -- Magnus Lie Hetland http://hetland.org
Re: Getting the mutable version of a type
On 2012-03-02 11:23:20 +, Ali Çehreli said: On 03/02/2012 02:18 AM, Magnus Lie Hetland wrote: I'm writing a template for generating data of some possibly immutable type -- e.g., a string. What I'm wondering is, is there some way of accessing the mutable version of an immutable type? Yes, std.traits.Unqual: http://dlang.org/phobos/std_traits.html#Unqual Aah -- awesome. Thanks! -- Magnus Lie Hetland http://hetland.org
Getting the mutable version of a type
I'm writing a template for generating data of some possibly immutable type -- e.g., a string. What I'm wondering is, is there some way of accessing the mutable version of an immutable type? I mean, I could do something like (for strings and related immutable arrays)... void func(T)(ref immutable(T)[] arg) { T[] res; ... arg = cast(immutable(T)[]) res; } But it would be useful to be able to write the same template for both mutable and immutable types, and just use something like void func(T)(ref T arg) { mutable(T) res; ... arg = cast(T) res; } Is there something like that? (E.g., a template in Phobos or something.) I guess I could do a match with an is() expression to extract the type, perhaps. -- Magnus Lie Hetland http://hetland.org
Re: Should uniform(-real.max, real.max) be inf?
On 2012-03-01 16:34:23 +, Ali Çehreli said: Since there are also sub-normal values between 0 and T.min_normal, it may make sense to use the range [T.min_normal, 1) and scale the result from there. But I haven't tested whether the distinct values in that range are equally distributed. I get similar results now that I did when I started with the range from -1 to 1, but I'm guessing it's my brain that's a little slow. I was perplexed that (for float) almost all the numbers had an exponent of 38, while only a few had 37, and none had anything else (in my limited tests). Bt that's just the problem with (at least my) "common sense" and exponentials/logarithms. There are, of course, ten times as many numbers with an exponent of 38 as there are with an exponent of 37 (and so on, down the line; c.f., the incompressibility lemma etc.). For testing, I might want some small numbers, too -- perhaps I should just generate the mantissa and exponent separately (maybe even throwing in some NaNs and Infs etc.) :) Thanks for your help, though. -- Magnus Lie Hetland http://hetland.org
Re: Should uniform(-real.max, real.max) be inf?
On 2012-03-01 16:34:23 +, Ali Çehreli said: I recommend reading this page: http://dlang.org/d-floating-point.html Thanks. Especially the ASCII graph there is very interesting. The number of distinct values between T.min_normal and 1 are equal to the distinct values between 1 and T.max . Ah -- right. Since there are also sub-normal values between 0 and T.min_normal, it may make sense to use the range [T.min_normal, 1) and scale the result from there. Hm. Seems reasonable. But I haven't tested whether the distinct values in that range are equally distributed. At the moment, I'm just using this for test-case generation, so anything close to a reasonable approximation is fine :) However: Perhaps it would be useful with a uniform!real() or the like in Phobos? Or is that (because of the vagaries of FP) a weird thing to do, inviting misunderstandings and odd behavior? Perhaps it's been left out for a reason? (Sounds sort of likely ;-) -- Magnus Lie Hetland http://hetland.org
Re: Should uniform(-real.max, real.max) be inf?
On 2012-03-01 10:52:49 +, Magnus Lie Hetland said: I could just use uniform(cast(T) -1, cast(T) 1)*T.max I guess (for some floating-point type T). Seems to work fine, at least. Aaactually, not so much. The output here seems to get about the same exponent as T.max. Which isn't all that surprising, I guess. (Then again, most floating-point numbers *are* pretty large ;-) So ... any suggestions? -- Magnus Lie Hetland http://hetland.org
Should uniform(-real.max, real.max) be inf?
What's the preferred way of generating a random floating-point number in the range of a given floating-point type? We have uniform!T() for integral types, but nothing similar for floats? And uniform(-real.max, real.max) (possibly tweaking the limits) seems to only return inf, which isn't terribly helpful. What's the standard thing to do here? I could just use uniform(cast(T) -1, cast(T) 1)*T.max I guess (for some floating-point type T). Seems to work fine, at least. Am I missing the obvious way to do it? -- Magnus Lie Hetland http://hetland.org
Re: More general Cartesian product
On 2012-02-29 14:24:36 +, Philippe Sigaud said: [snip] Thanks for the response. In the meantime, I also hacked together a simple version of what I needed (see below), but I'll look into the references you provided as well :) void forall(alias func, size_t lvl=0, T...)(T args) { static if (lvl == args.length) { func(args); } else { foreach (e; args[lvl]) { forall!(func, lvl+1) (args[0..lvl], e, args[lvl+1..$]); } } } -- Magnus Lie Hetland http://hetland.org
More general Cartesian product
Hi! I have a need for a Cartesian product of multiple ranges. I see there's been a discussion here (Dec 2011) as well as a request posted (#7128). It seems to me that the request deals with a multidimensional product -- which is what I need -- while the implementation by Timon Gehr deals only with the two-dimensional case. I guess I could apply it in a nested fashion, but there's still the issue of flattening the result. My application is a template along the lines of void forall(alias func, T...)(T args) { ... } which would call func with every combination of parameters taken from the ranges in args. So that, for example, forall!foo([1, 2], ["a", "b"]) would yield four calls, from foo(1, "a") to foo(2, "b"). But the thing is that I'd like an arbitrary number of arguments. Sure, I could set an upper limit and hard-code the cases -- but there must be a prettier way? I've made some stabs at a recursive version, DMD complaining all the while. Any pointers? (Now, I would eventually like to do more complex versions, using only a *subset* of the Cartesian product (for, e.g., all-pairs testing or combinatorial testing).) -- Magnus Lie Hetland http://hetland.org
Re: DbC bug?
On 2012-02-23 15:59:18 +, H. S. Teoh said: Looks like a compiler bug. You should never be able to access invalid values. Indeed. After spending quite a while whittling down my code, I've posted the following snippet as issue #7599: module main; import std.conv; class Class { void method(uint arg) in { // assert(arg + 1); // Uncomment to prevent bug } out { assert(arg == 0, "BUG: arg == " ~ to!string(arg)); } body {} } void main(string[] args) { (new Class).method(0); } -- Magnus Lie Hetland http://hetland.org
DbC bug?
I think I've stumbled across a DbC bug. In an out-block, I have the assertion `assert(id < objs.length);`. Now, if I don't have an in-block, this fails. However, if I add an in-block (with basically any code that isn't optimized away, or so it seems), the assertion succeeds. (Before this was an assertion, the failure was a range violation from objs[id]; the behavior is equivalent for that.) And this happens even though both id and objs are const...(!) And: If I place the same assertion just before the return statement (which just returns the result, without any computation), the assertion before return succeeds, but the one immediately inside the out block fails. Unless, of course, there is an in block, which magically fixes everything (without really doing anything). It seems that the id variable (a parameter of the method) is actually undefined in the out-block, and that this is the reason for the error. (The program is run with the same random seeds, but the id variable, which *should* be in 0..1000, ends up with varying values such as 1609528144, 1653547856 or 1816621904. I'm guessing this is a bug in the DbC functionality, somehow? Is it a known bug? (Couldn't find anything relevant -- but then again, I wasn't sure exactly what to search for...) My code runs lots of experiments, and this only happens after the method has been used a *lot* (i.e., this doesn't happen all the time -- though it *does* happen every time the program is run) -- which means producing a minimal example would require some effort... :-}
Re: GG bug? (OS X Lion, DMD 2.054)
On 2011-08-04 13:01:19 +, Jacob Carlborg said: Since it's just the runtime that's been changed in this case, perhaps you just can compile the runtime and replace that with what's in the release. I guess so. I've just starting compiling/linking stuff together -- I'll see how it goes. (It can be useful to have the most recent version; ideally, it should have fewer bugs ;) If that fails, I could try just the runtime, as you suggest. -- Magnus Lie Hetland http://hetland.org
Re: GG bug? (OS X Lion, DMD 2.054)
On 2011-08-04 12:27:54 +, Alex Rønne Petersen said: Hi, You can see my blog for Linux: http://xtzgzorex.wordpress.com/2011/07/31/d-building-dmd-and-phobos-on-linux/ For others trying to do the same (i.e., compile this stuff in OS X Lion), one change is needed in posix.mak: Change ... SDK=/Developer/SDKs/MacOSX10.5.sdk #SDK=/Developer/SDKs/MacOSX10.6.sdk ... into ... SDK=/Developer/SDKs/MacOSX10.5.sdk #SDK=/Developer/SDKs/MacOSX10.6.sdk SDK=/Developer/SDKs/MacOSX10.7.sdk (or equivalent). -- Magnus Lie Hetland http://hetland.org
Re: GG bug? (OS X Lion, DMD 2.054)
On 2011-08-04 12:27:54 +, Alex Rønne Petersen said: Hi, You can see my blog for Linux: http://xtzgzorex.wordpress.com/2011/07/31/d-building-dmd-and-phobos-on-linux/ Thanks! -- Magnus Lie Hetland http://hetland.org
Re: GG bug? (OS X Lion, DMD 2.054)
On 2011-08-03 14:57:57 +, David Nadlinger said: This seems to be exactly same problem I reported to the NG some days ago. It is caused by ASLR being enabled for 32bit applications on Lion too, and kennytm is to be credited for tracking this down to a fixed stack bottom in the druntime code: https://github.com/D-Programming-Language/druntime/pull/43. The fix has already been merged into master, please use that for OS X development until the next DMD release. Sorry for being a n00b here, but ... what's the intended way of using the Git version? It seems to be split into five different repos...? Do I have to assemble a full distro myself, or am I just missing something obvious? (I'm assuming the latter, really ;) -- Magnus Lie Hetland http://hetland.org
Re: GG bug? (OS X Lion, DMD 2.054)
Note that an explicit call to GC.collect isn't necessary. Whenever collection occurs, the collectors seems rather indiscriminate, collecting things it shouldn't, resulting in bus errors. When I disable the GC, my code runs just fine. (My production code, that is. There are still mysterious, probably Lion-related, bugs in my test suite...) -- Magnus Lie Hetland http://hetland.org
GG bug? (OS X Lion, DMD 2.054)
I upgraded from OS X Snow Leopard to Lion recently (on a 32-bit iMac), and when I tried to run my D code afterward, I suddenly ran into all kinds of interesting problems (lots of failed assertions in my tests, and bus errors in my actual runs...). Still cleaning stuff up, but I've isolated at least one thing that seems to be a bug, and that wasn't there before I upgraded. Now, I upgraded from DMD 2.052 to 2.054 before doing any extensive debugging, so I'm not 100% sure this specific problem was there in 2.052 as well, but I *think* so (i.e., making the switch to Lion the triggering factor). Anyway, here's some code: import std.exception, core.memory; class Foo { bool bar; } void main() { auto f = new Foo; f.bar = true; //GC.collect(); enforce(f.bar); } Works well, unless you uncomment the GC call, in which case a bus error occurs (at least for me). Seems the collector is a bit over-eager...? -- Magnus Lie Hetland http://hetland.org
Re: Polymorphism problem w/local functions?
On 2011-07-18 18:10:47 +0200, Jonathan M Davis said: Well, technically-speaking, that's not really polymorphism, since the choice of function is decided at compile time (polymorphism would be dealing with overridden functions than overloaded ones), Right ... thought static overloading was considered a form of polymorphism as well. Aanyway... :D but I suppose that that's not really here nor there. Right :) In any case, no you can't overload nested functions. You've never been able to, and you still can't do it. I don't know _why_ such a restriction exists, but it does. Feel free to open up an enhancement request for it. I don't know that it'll do much good, but maybe you'll luck out. Not knowing why the restriction exists in the first place, I don't know what the chances are of that restriction being removed. For all I know, it's an Walter's TODO list. I see. Not really critical. As I've been thinking about the problem I was working on, I guess dynamic (i.e., "real") polymorphism is what I need anyway; I guess the (only?) way to do that would be to have a method on the objects in question. (Right...? There are no other dynamic dispatch mechanisms that I'm forgetting, other than type-based switch statements?) Thanks, - M -- Magnus Lie Hetland http://hetland.org
Polymorphism problem w/local functions?
Is it intended that local functions can't be polymorphic? Example: void foo(int x) {} void foo(string x) {} void bar() { void foo(int x) {} void foo(string x) {} } void main() { } The error (at line 6) is "declaration foo is already defined". The code compiles if you comment out at least one of the local functions (but not if you, for example, comment out the global ones, of course). Is this a bug, or am I just missing the reasoning behind it? Any workarounds? (I'm still at 2.052, so maybe this works in the new version?) -- Magnus Lie Hetland http://hetland.org
Re: "Before and after" in contracts?
On 2011-04-11 18:42:18 +0200, bearophile said: Your need is perfectly natural it's named "old" values or prestate in contract programming, and currently it's probably the biggest hole in the D contract programming. It was discussed three or four times, like: [snip] Interesting. I don't know if Walter is willing someday to fill this hole of the D DbC. It seems the prestate thing hasn't been done because it's a bit ambitious? I mean, the automatic part (which would be totally *kick-ass*, of course). For me, I'd be happy if I could simply declare and initialize the variables myself somehow before the body is executed, and then check them in the out-block. In my opinion is good to bugger now and then the main D newsgroup about this, to help Walter&Andrei understand that there are some programmers that care for this feature of DbC. Is there a feature request on this that I could add my vote to? If not, perhaps it's worth creating one? If not, I guess I could just post a "bump" to the D group :-} -- Magnus Lie Hetland http://hetland.org
Else clauses for loops
Hi! A feature I use surprisingly often in Python is the else clause on loops. Is there something similar in D? Basically, the idea is that your loop is "looking for something" (or some condition), and that you'll break out of it if you find what you're looking for. If no break occurs, the else clause is executed. It makes for quite clean code in many cases, IMO. The alternative can be a flag variable, I guess, or a goto-statement (to right after the "else" bit) instead of a break. Or put it in a function, and use a return instead of a break ... or use scope() somehow, perhaps. I see that the feature has been requested a few years ago [1], so there might not be that much demand for this sort of thing. Is there perhaps a D idiom here already? [1] http://d.puremagic.com/issues/show_bug.cgi?id=2304 -- Magnus Lie Hetland http://hetland.org
Re: "Before and after" in contracts?
On 2011-04-11 16:32:36 +0200, Kai Meyer said: I don't know if I can speak to the philosophical points here, but you can put your attribute declarations in a version block, and as long as the usage of that attribute is only used when that version is used, you should be fine. Yeah, that's what I've got right now. Just seems odd to need to use attributes for this sort of thing. Also, it's rather brittle -- for example, if the function (directly or indirectly) calls itself. Then two (or more) pairs of in/out blocks will manipulate the same attribute... Seems like a variable that would be local to one specific in/out instantiation (or stack frame) would be preferable. I guess I could just use a local variable (guarded by version()) and then have an assert() near the end of the function. Probably a better solution... -- Magnus Lie Hetland http://hetland.org
"Before and after" in contracts?
I'd like to write a contract for a method to ensure that a given attribute does not decrease when calling the method. In order to do that, I need to store the "before" value, and compare it to the after value. My first intuition was to declare a variable in the in-block, and then access that in the out-block. No dice, it seems. I tried declaring one in the body (with a version(unittest) qualifier). Still no dice. I ended up using a separate *attribute* for this, which seems particularly ugly to me. Is it philosophically "wrong" to write stateful "before/after" contracts like this? If not, can it be done in a less ugly manner? (Or should I just learn to like this way of doing it?) -- Magnus Lie Hetland http://hetland.org
Can I use a delegate as a template parameter? (Issue 2962?)
A while ago, I wrote something like this: void C(alias foo)() { void bar() { foo(); } bar(); } void B(T)(uint x=2) { uint foo() { return x; } C!foo(); } It worked well, so I didn't think any more about it. Then suddenly, I started getting the following error: ./path/to/foo.d(12): Error: function path.to.foo.B!(real).B compiler error, parameter 'x', bugzilla 2962? Assertion failed: (0), function toObjFile, file glue.c, line 729. This only happens when I compile with -inline, and error disappears if I make certain really minor changes to which modules are imported where (currently 17 basically empty modules are involved in the minimal case I've been able to produce), so the compiler behavior seems like a bug. As Don says in a comment to 2962, "This is really tough, it's an order-of-evaluation issue. When generating the code for a template, which has a local variable as an alias parameter, the alias parameter MUST be created before the code for template is." The error message also seems different from that of issue 2962 (which DMD dutifully points me toward :), so I'm uncertain about whether it's the same issue. What does it look like to you guys? Also, aside from the erratic DMD behavior, I'm guessing my code might be invalid, and shouldn't have worked in the first place. After all, x is a run-time argument, and is part of foo, which functions as a compile-time argument. I mean, the set-up *could* work (and, in fact, generally seems to do so), but it might be a bit problematic? This way of doing it seems like the most practical for my current use, though... (I.e., I'd like foo to be inline-able, and have access to x.) -- Magnus Lie Hetland http://hetland.org
Re: How do you use BinaryHeap with Array (or just make a growable heap)?
On 2011-03-28 20:24:55 +0200, Jonathan M Davis said: Well, Array definitely shouldn't be a random access range. The range for it (which you'd typically get by slicing it) would be random access, but the container itself isn't a range of any kind. Containers aren't ranges (barring the oddities of dynamic arrays). I've never used BinaryHeap, but glancing at it, my guess would be that the correct solution (if you want to use Array with it) is to create an Array and then pass its range to heapify: Array!uint a; //... put stuff in a. auto heap = heapify(a[]); I'm not sure if that's growable or not though. Hm. I can't even get the slicing to work: /path/to/phobos/std/container.d(2436): Error: function std.container.Array!(uint).Array.Range.opSlice (uint a, uint b) is not callable using argument types () Glancing at BinaryHeap, it'll work with arrays though, so you don't need to use Array. Hm. The docs say "If Store is a range, the BinaryHeap cannot grow beyond the size of that range. If Store is a container that supports insertBack, the BinaryHeap may grow by adding elements to the container." So it seems that a container (such as Array, which has insertBack) should be usable, according to the docs. And an array/slice would not be growable. (At least, it isn't growable in practice.) See also: http://www.digitalmars.com/d/archives/digitalmars/D/std.algorithm.BinaryHeap_88811.html What I'm looking for is a completely standard priority queue, where I can add and remove objects, and not have to know the maximum size beforehand. I'd also like to have tuple entries, but it seems that BinaryHeap has trouble with that as well... I don't know what the ideal container to use with a BinaryHeap is though. Also, in my experience, Array is pretty buggy at this point, so I'm not sure how far you'll get with it. Yeah, it seems to be. At the moment, I've just reimplemented BinaryHeap myself (with a subset of the Phobos API), so that it can handle arrays of tuples (which I couldn't get std.container.BinaryHeap to accept). I then wrapped it in a PriorityQueue class, which takes care of resizing the array (and having BinaryHeap switch to the possibly reallocated new one). Not an ideal solution, but at least it works. -- Magnus Lie Hetland http://hetland.org
How do you use BinaryHeap with Array (or just make a growable heap)?
I need a (growable) binary heap, and I'm trying to avoid writing one myself (which isn't too hard, of course :) ... but for some reason I can't figure out how to use Phobos to do it. I've seen stated (e.g., by Andrei and in the docs) that the standard way is combining BinaryHeap with an Array. Which is fine with me. Except I can't make it work. E.g., I try: Array!uint A; auto Q = heapify(A); The error is /path/to/phobos/std/container.d(2658): Error: template instance BinaryHeap!(Array!(uint)) does not match template declaration BinaryHeap(Store,alias less = "a < b") if (isRandomAccessRange!(Store) || isRandomAccessRange!(typeof(Store.init[]))) /path/to/phobos/std/container.d(2658): Error: BinaryHeap!(Array!(uint)) is used as a type When I check it out, it seems that isRandomAccessRange!(Array!uint) returns false (and it doesn't, AFAIK, have an init), which means that the error makes sense. Does this mean... 1. That Array isn't, and shouldn't be, a random access range? 2. That Array can't, and shouldn't be (despite official statements to the contrary) be used with BinaryHeap? (I suspect the answer to both is "you're doing it wrong" ;) And, of course, my main question: 3. How do you (canonically) make a growable heap using Phobos? -- Magnus Lie Hetland http://hetland.org
Re: Bug in tuple comparison?
On 2011-03-24 18:25:30 +0100, bearophile said: Magnus Lie Hetland: I guess this is getting old by now ... but I've come across yet another bug :-> The out(result) turns the result into a const, Riiight! Yes, I've seen that it's const, and (naughtily) cast away the constness (without modifying anything) in some cases. It didn't occur to me that that was the problem here. :) (In my original program, I didn't notice that I had gotten one of the values from outside the out-block, while the other was from the result. I guess I was "primed" to think that that wasn't the problem ;) So the issue, then, I take it, is that you *can* compare a non-const tuple to a const-tuple, but you *cannot* compare a const-tuple to a non-const tuple (as per casting rules)? Makes sense. Would have been nice with a slightly more obvious error message, but I guess that's always a problem with templates in any form ;) Aanyway -- glad the bug was just in my code/brain :D Thanks for the help, - M -- Magnus Lie Hetland http://hetland.org
Bug in tuple comparison?
I guess this is getting old by now ... but I've come across yet another bug :-> This one is a bit obscure, and deals with comparing tuples in contracts. It seems that some type information about the result is lost when entering an out-block, or something. At least, DMD (2.052, OS X) is unable to infer types properly, and is therefore unable to compare tuples in some cases. Sample program follows. (Similar behavior occurs for other comparison operators as well.) import std.typecons; T[] func(T)(T[] arg) out(result) { auto a = result[0]; auto b = arg[0]; auto c = result[0]; // assert(c < a); // Doesn't work // assert(a < c); // Doesn't work // assert(c < b); // Doesn't work assert(b < c); // Works } body { return arg; } void main() { alias Tuple!(real, uint) Entry; func(new Entry[100]); } The error (when uncommenting one of the lines that don't work, e.g., line 7) is: tuplecmpbug.d(7): Error: template std.typecons.Tuple!(real,uint).Tuple.opCmp(R) if (isTuple!(R)) does not match any function template declaration tuplecmpbug.d(7): Error: template std.typecons.Tuple!(real,uint).Tuple.opCmp(R) if (isTuple!(R)) cannot deduce template function from argument types !()(const(Tuple!(real,uint))) I take it this is a bug (or am I just missing something)? Is it a known bug? (Sorry if it's in the tracker; it can be hard to find equivalents there...) -- Magnus Lie Hetland http://hetland.org
Re: Bug w/tuple of custom types?
On 2011-03-21 18:40:07 +0100, Steven Schveighoffer said: If you looked and couldn't find it, it doesn't hurt to add it. Worst case -- it gets marked as a duplicate. OK. Perhaps I should just start doing that, rather than asking here about every bug I find. (I seem to come across new ones every day ;-) Note that typedef is eventually going to be deprecated. I'd suggest using alias unless you have a need to force uints not to be castable to oid_t. Ah. That sort of makes the bug a bit less relevant :-> Actually, the typedef *was* to prevent that casting, because I inadvertently used an uint that was of a semantically different kind, and got a hard-to-spot bug -- so I thought I'd try to prevent that by using the type system. Any way to do that without (to be deprecated) typedef? -- Magnus Lie Hetland http://hetland.org
Re: Deducing types for function templates
On 2011-03-15 21:13:36 +0100, Michel Fortin said: Oh, it's much older than that: http://d.puremagic.com/issues/show_bug.cgi?id=2128 I'm not sure it's the same thing, but I realize it's hard to say given Magnus in his original post didn't mention how he attempts to instantiate the template. Hm. I've gone back to it now, and, sadly (as opposed to for the other bugs I've encountered :) I didn't isolate and save the related code -- so now I'm unable to reproduce the const problem. (Who knows ... maybe I was just trying to pass it on as an un-const parameter or something? Might very well have been a bug on my part.) Here's some sample code for the other part of my question, though (which might not have been as unclear in the first place?). class Foo(T) { T foo; } template baz_t(T) { alias real function(T, T) baz_t; } Foo!T foo(T)(T[] bar, baz_t!T baz) { return new Foo!T; } real frozz(uint x, uint y) { return 4.2; } void main() { uint[] x = [1, 2, 3]; auto f = foo(x, &frozz); } The error is: inferencebug.d(19): Error: template inferencebug.foo(T) does not match any function template declaration inferencebug.d(19): Error: template inferencebug.foo(T) cannot deduce template function from argument types !()(uint[],real function(uint x, uint y)) -- Magnus Lie Hetland http://hetland.org
Bug w/tuple of custom types?
Sample program: import std.typecons; typedef uint oid_t; void main() { Tuple!(uint,uint) key; // Tuple!(oid_t,oid_t) key; // Doesn't work } If I use the last tuple instead of the first, I get the following compiler error with DMD 2.052 in OS X: /path/to/src/phobos/std/format.d(1579): Error: function std.format.formatValue!(Appender!(string),oid_t,immutable(char)).formatValue is deprecated /path/to/src/phobos/std/format.d(306): Error: template instance std.format.formatGeneric!(Appender!(string),oid_t,immutable(char)) error instantiating /path/to/src/phobos/std/typecons.d(507):instantiated from here: formattedWrite!(Appender!(string),immutable(char),oid_t) It seems that std.typecons is using a deprecated formatting API, which is triggered by my use of a custom type? And ... I guess this would be a bug? (I looked in the tracker, and couldn't find it there already.) -- Magnus Lie Hetland http://hetland.org
Deducing types for function templates
I've got a function template along these lines: Foo!T foo(T)(T[] bar, real function(T,T) baz) { ... } The main reason I'm using this is that it seems necessary to use a function, rather than a type (such as Foo), if you want the compiler to deduce the compile-time parameters. (Right?) Now ... this works just fine. However, if I try to add "const" before "T[]", DMD no longer groks it. Is that how it shold be? Seems awkward to me... (Or maybe I'm just doing it wrong?) And a followup question: Writing out the type of baz like this (in several places) is also a bit awkward. I'd like to have a template so I could just do Foo!T foo(T)(T[] bar, baz_t!T baz) { ... } However, I haven't been able to define such a template without running into the same problem (i.e., that DMD no longer can deduce what T should be from my arguments). Any pointers? -- Magnus Lie Hetland http://hetland.org
Re: "Semi-const" methods?
On 2011-03-14 00:17:18 +0100, Jonathan M Davis said: So, if you don't actually manage to _really_ be logically const, or if you do this with an immutable object (which would likely result in a segfault), you _are_ going to have incorrect code. On the whole, I'd advise just not using const when you need logical const, but if you're _very_ careful, you can get away with it. But thanks to immutable, it can be _very_ dangerous to cast away constness in a const function unless you're _very_ careful. You really should check out this question on stackoverflow and the answers that go with it: http://stackoverflow.com/questions/4219600/logical-const-in-d Thanks for the insights + tip :) -- Magnus Lie Hetland http://hetland.org
Re: "Semi-const" methods?
On 2011-03-14 11:51:09 +0100, Mafi said: I found away which doesn't use casts or bugs. Just use delegates/closures. Nice :D -- Magnus Lie Hetland http://hetland.org
Re: "Semi-const" methods?
On 2011-03-13 23:32:34 +0100, Magnus Lie Hetland said: (Still open to schooling on the design part of this, though. Perhaps declaring a method as const is no good when it's not *really* const? For now, I'm just doing it to check that I don't inadvertently change things I don't want to change.) Actually, I have a local (recursive) traversal function in the method I was talking about. Ended up not declaring the method as const, but declaring the argument of the traversal function as const. No misleading const declarations "outside", and I get the automatic checks that I want. -- Magnus Lie Hetland http://hetland.org
Re: "Semi-const" methods?
On 2011-03-13 23:27:14 +0100, Magnus Lie Hetland said: Any other ideas on how to handle this sort of "mostly const" or "const where it counts" stuff? Perhaps my design intentions here are off to begin with?-) OK -- a *little* quick on the trigger there. My solution: Declare the method const, and assign the non-essential cache stuff to local variables, casting away the constness. (Still open to schooling on the design part of this, though. Perhaps declaring a method as const is no good when it's not *really* const? For now, I'm just doing it to check that I don't inadvertently change things I don't want to change.) -- Magnus Lie Hetland http://hetland.org
"Semi-const" methods?
I have a data structure that's generally static (const, or even immutable), but it has some utility storage, which caches certain results during use. This caching etc. doesn't really affect the semantics of the main object, and are reset between operations, so I think it still would be useful to declare (and statically check) that certain methods don't modify any of the *rest* of the structure (i.e., the "main parts"). I *could* declare the methods const, and pass in a second object (a non-const parameter) for the caching etc. Or I cast the relevant parts to const (assigning them to local variables) early on in the relevant methods (dropping the const modifier on the method itself -- sort of a bummer). Any other ideas on how to handle this sort of "mostly const" or "const where it counts" stuff? Perhaps my design intentions here are off to begin with?-) -- Magnus Lie Hetland http://hetland.org
Re: "foo.bar !in baz" not allowed?
On 2011-03-13 21:27:27 +0100, spir said: On 03/13/2011 07:58 PM, Magnus Lie Hetland wrote: For some reason, it seems like expressions of the form "foo.bar !in baz" aren't allowed. I suspect this is a grammar/parser problem -- the bang is interpreted as a template argument operator, rather than a negation operator, [snip] Would be nice to copy the error, wouldn't it? template argument expected following ! Ah. I thought my explanation (see above) made that clear. Anyway, this is definitely a bug in my opinion. Turns out it's an old one. Sorry about that: http://d.puremagic.com/issues/show_bug.cgi?id=4159 -- Magnus Lie Hetland http://hetland.org
"foo.bar !in baz" not allowed?
For some reason, it seems like expressions of the form "foo.bar !in baz" aren't allowed. I suspect this is a grammar/parser problem -- the bang is interpreted as a template argument operator, rather than a negation operator, and there's really no need to make that interpretation when it is immediately followed by "in". This suspicion is strengthened by the fact that "bar !in baz" is fine, as is "(foo.bar) !in baz". Should I file this as a bug? Small sample program: struct Foo { uint bar; } struct Baz { bool opIn_r(uint e) { return false; } } void main() { Baz baz; Foo foo; auto res = (foo.bar) !in baz; res = !(foo.bar in baz); // res = foo.bar !in baz; // Not OK... uint frozz; res = frozz !in baz; } -- Magnus Lie Hetland http://hetland.org
Re: Iterating over 0..T.max
On 2011-03-09 21:24:57 +0100, Kai Meyer said: I don't see how that works in dmd2, and I don't have much experience with dmd1, so I'll admit that this may be different on dmd1. Derp. I didn't mean bool -- I was talking about byte. (Which should make quite a bit more sense, given that I'm talking about a limit of 256... :D) And, for the record, I'm using DMD 2.052 (OS X). Just replace bool with byte in your program, and it should compile. Sorry for the brain fart ;) -- Magnus Lie Hetland http://hetland.org
Iterating over 0..T.max
In a (template) data structure I'm working on, I had the following thinko: auto a = new T[n]; foreach (T i, ref e; a) { e = i; } Then I instantiated it with T=bool, and n=256. Infinite loop, of course -- the problem being that i wraps around to 0 after the last iteration. Easily fixed, and not that much of a problem (given that I caught it) -- I'll just use e = cast(T) i. (Of course, even with that solution, I'd get wrap problems if n=257, but I just want to make sure I allow T.max as a size.) But I'm wondering: given D's excellent valua range propagations and overflow checking, would it be possible to catch this special case (i.e., detect when the array can be too long for the index type)? Or are any other safeguards possible to prevent this sort of thing? -- Magnus Lie Hetland http://hetland.org
Re: Growable BinaryHeap: use w/Array?
On 2011-03-06 14:58:10 +0100, Magnus Lie Hetland said: [corrected the example below, replacing int with string] that works just fine. However, if I try alias Tuple!(real,string) Entry; Array!Entry Q; then I get the following errors: container.d(1549): Error: this for _data needs to be type Array not type Payload container.d(1550): Error: this for _data needs to be type Array not type Payload container.d(1551): Error: this for _data needs to be type Array not type Payload Actually, now, running the same program, I get a *different* error message: container.d(1502): Error: template instance template 'hasElaborateDestructor' is not defined container.d(1502): Error: hasElaborateDestructor!(Tuple!(real,string)) is not an expression As far as I know, I haven't changed anything in the ecosystem, and the code is the same (which seems a bit magical...). Anyway: this doesn't seem right ... should I file a bug? -- Magnus Lie Hetland http://hetland.org
Re: Growable BinaryHeap: use w/Array?
On 2011-03-06 15:00:29 +0100, David Nadlinger said: On 3/6/11 2:58 PM, Magnus Lie Hetland wrote: alias Tuple!(real,int) Entry; Array!Entry Q; [...] alias Tuple!(real,int) Entry; Array!Entry Q; Is it just me, or is there really no difference between the two snippets? ;) $(WITTY_REPLY) ;-) The one that fails should have string (or some other reference type, perhaps) rather than int. Copy/paste fail :D -- Magnus Lie Hetland http://hetland.org
Re: Growable BinaryHeap: use w/Array?
On 2011-03-06 14:37:19 +0100, Magnus Lie Hetland said: Just wondering: If I want a growable binary heap (I'd be open to other priority queue structures, for that matter ;), is the standard way in D (w/Phobos) to combine std.container.BinaryHeap with std.container.Array? Another thing ... when I use priority queues, I'm usually not interested in just having a set of priorities -- the payload data is what it's all about. So I thought I'd just use an Array of Tuples, managed by BinaryHeap (possibly with a custom comparison, to avoid comparing the payloads). But perhaps that's not a good idea? When I try alias Tuple!(real,int) Entry; Array!Entry Q; that works just fine. However, if I try alias Tuple!(real,int) Entry; Array!Entry Q; then I get the following errors: container.d(1549): Error: this for _data needs to be type Array not type Payload container.d(1550): Error: this for _data needs to be type Array not type Payload container.d(1551): Error: this for _data needs to be type Array not type Payload It seems the lines that are being referred to are GC.removeRange(_data._payload.ptr); free(_data._payload.ptr); _data._payload = newPayload; though I may be wrong about that. Is this a bug in Array? Am I using it wrong? And what would be the recommended "best practice" for a priority queue with payload data in D (using Phobos)? (I could just write one myself, but that seems sort of wasteful ;) -- Magnus Lie Hetland http://hetland.org
std.gc doc page
It seems std.gc is no longer available -- or, rather, that it is now core.memory? Is there a reason why this page exists, and has a link in the sidebar? http://www.digitalmars.com/d/2.0/phobos/std_gc.html (Yes, the documentation is for core.memory, but the page name/link name is std.gc. Also, there's no core.memory link in the sidebar...) -- Magnus Lie Hetland http://hetland.org
Growable BinaryHeap: use w/Array?
Just wondering: If I want a growable binary heap (I'd be open to other priority queue structures, for that matter ;), is the standard way in D (w/Phobos) to combine std.container.BinaryHeap with std.container.Array? Any reason why BinaryHeap can't deal with ordinary dynamic array appending, or appender instances, for that matter? Or, to put the questions a bit differently: Is there a reason why std.array doesn't have an insertBack method (that BinaryHeap can use) either defined for dynamic arrays or for std.array.Appender? Just trying to figure out what's what here :) -- Magnus Lie Hetland http://hetland.org
Re: Overriding iteration
On 2011-03-04 19:06:34 +0100, Jonathan M Davis said: On Friday, March 04, 2011 09:13:34 spir wrote: On 03/04/2011 05:43 PM, Steven Schveighoffer wrote: [snip] opApply should work but it is supposed to be slower. Defining range primitives directly on the object/container cannot work as of now, unfortunately, because of a pair of bugs (conflicts in formatValue template definitions between struct/class on one hand and ranges on the other). You don't _want_ range primitives directly on the container. That would mean that everything in your container goes away when you process it. That was the point of my original question, yes :) In TDPL, where Andrei discusses overloading foreach, he has two main examples -- one using opApply, and one using such a self-destructive container. I think (as I said in my post) that what saves that list is that it's a struct, so it's copied by the initial assignment of the foreach statement. You _want_ to have a separate type which is a slice of our container and has the range primitives. Exactly. That was what I was asking for. Now, it could very well be that foreach(v; container) should be calling opSlice on the container, allowing you to feed the container to foreach directly instead of having to slice it yourself foreach(v; container[]) but that's just syntactic sugar. Sure. And judging from the other responses (and from TDPL), the fact that this doesn't currently work is just a bug. You don't want to actually treat your container like a range. Ranges should be slices of containers, not containers themselves. Well, it would still be nice to have things be consistent -- and in order for the opSlice approach to be consistent with the opApply approach (so a client needn't know how iteration is implemented for a given container), it seems reasonable to me to have foreach directly run on a slice of your container (i.e., implicitly calling []). But as this seems to be the way it is (save for the current bug), I guess it's sort of a moot point. I certainly agree with your point, though. In Python, too, iterators (i.e., ranges) and iterables (i.e., containers) are separate concepts. You can iterate over an iterable, and the loop then automatically extracts an iterator. As this is The Way to Go, it makes sense to me that it's automatic/implicit. -- Magnus Lie Hetland http://hetland.org
Re: Overriding iteration
On 2011-03-04 17:46:39 +0100, Simen kjaeraas said: Simen kjaeraas wrote: [snip] Found it: http://d.puremagic.com/issues/show_bug.cgi?id=5605 Oo -- nice :) (That it should work, that is; not that it doesn't ;) -- Magnus Lie Hetland http://hetland.org
Re: Overriding "in" operator
On 2011-03-04 18:08:08 +0100, spir said: Didn't even know 'in' can be defined with opBinary... I use opIn_r ('r' for right side, since the container stand on the right of the expression) everywhere, and it works fine. Huh. Cool. Works like a charm. Seems cleaner like the opBinaryRight solution, really. I just didn't know of it :) -- Magnus Lie Hetland http://hetland.org
Re: Overriding "in" operator
On 2011-03-04 17:06:29 +0100, Mafi said: If you try to use it in the manner of `something in classWhichDefinesThisOpBinary` then it doesn't work because operator overloading normally overloads on the left operand (ie something). Use opBinaryRight(string op)(...) if(...) to get it working. Aaah. That makes sense. And works. *But*: I copied my code from Phobos :D If you search for "in", with the quotes, in std/container.d, you'll find two occurrences. The actual live use (in RedBlackTree) is opBinaryRight (which makes sense), but in the dummy class, TotalContainer, which is described as "an unimplemented container that illustrates a host of primitives that a container may define", uses just opBinary. The doc-comment says that "$(D k in container) returns true if the given key is in the container". So ... a "bug", I guess? (One that isn't really executed -- but still...) Worth reporting? Anwyay: Thanks for the clarification :) -- Magnus Lie Hetland http://hetland.org
Overriding iteration
From what I understand, when you override iteration, you can either implement the basic range primitives, permitting foreach to destructively iterate over your object, or you can implement a custom method that's called, and that must perform the iteration. The destructiveness of the first option can, of course, be mitigated if you use a struct rather than a class, and make sure that anything that would be destroyed by popFront() is copied. What I'm wondering is whether there is a way to do what Python does -- to construct/return an iterator (or, in this case, a range) that is used during the iteration, rather than the object itself? I'm thinking about when you iterate directly over the object here. As far as I can see, the solution used in the std.container is to use opSlice() for this functionality. In other words, in order to iterate over container foo, you need to use foreach(e; foo[])? Is there no way to get this functionality directly (i.e., for foreach(e; foo))? -- Magnus Lie Hetland http://hetland.org
Overriding "in" operator
I'm writing a collection with functionality for membership checking. I thought it would be nice to use the "in" operator. In the docs for std.collections I surmise that this is the standard way to go. From the source code, I see there's no special opIn, but that it can be done with the more general... bool opBinary(string op)(T k) if (op == "in") { ... } Here T is, of course, a compile-time argument of the surrounding struct or class. So ... this is used in the the Phobos source in the DMD 2.052 distro (if I'm not mistaken), but I can't get dmd 2.052 to accept it? I keep getting the error message "Error: rvalue of in expression must be an associative array, not Foo!(uint)". I guess either that this is a recent feature -- I didn't see it mentioned in Andrei's book -- and that my Phobos source is too recent for my dmd ... or that I'm doing something wrong elsewhere in my code, preventing the operator overloading to take force. Suggestions/solutions?-) -- Magnus Lie Hetland http://hetland.org
Re: Two questions about "%a"
On 2011-03-04 03:16:50 +0100, Nick Sabalausky said: I'm no floating-point expert, but I would think that the only way to get an exact representation would be to output the raw data in hex (or binary, or octal, etc): writef("0x%X", cast(ulong)1.2); That's also an option, certainly. Then I could just write it as a decimal integer, I guess. But the point of hex-literals for floats is precicely that they can represent floats exactly (even though it may not *look* like it, as in this case, because lots of digits are required to approximate the decimal value 1.2). So using those shold be safe -- and perhaps more easily read on other platforms, for example (byte order), or into floats with other precisions or the like. Thanks for the suggestion, though :) -- Magnus Lie Hetland http://hetland.org
Re: @property ref foo() { ...} won't work...?
On 2011-03-01 13:20:18 +0100, Steven Schveighoffer said: On Tue, 01 Mar 2011 07:19:21 -0500, Lars T. Kyllingstad wrote: On Tue, 01 Mar 2011 12:25:30 +0100, Magnus Lie Hetland wrote: 2. How can I make r.front = foo work, when I only have r.front(), returning a ref (which seems like it is used in actual code)? I think this is a bug, but I'm not entirely sure. It is most definitely a bug. Please file. Done. -Steve -- Magnus Lie Hetland http://hetland.org
Two questions about "%a"
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? 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?) -- Magnus Lie Hetland http://hetland.org
@property ref foo() { ...} won't work...?
In Andrei's book, as well as in the Phobos source, there are property getters that return refs, as in... @property ref T front() { return _payload[0]; } ... and code that uses this with simple assignments, such as: r.front = foo; For some reason, I can't get this to work in my code :-/ DMD seems to insist that I add a setter as well (i.e., @property T front(T val) { return _payload[0] = val; }). On the other hand, I *do* get r.front() = foo; to work. That works well even without @property, of course; and r.front fails even without @property. Then, again, if I write both the getter (front()) and the setter (front(T)), that works even without @property (which, then, seems rather redundant?). So ... I guess I have two questions: 1. What's the point of @property (when it seems I get the same functionality without it)? 2. How can I make r.front = foo work, when I only have r.front(), returning a ref (which seems like it is used in actual code)? -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-27 02:33:46 +0100, Jonathan M Davis said: [snip lots of useful stuff] Thanks for your patience, and more useful clarifications. I think I get it now (but I may very well be wrong ;) - M -- Magnus Lie Hetland http://hetland.org
Re: Is std.cover deprecated or gone?
On 2011-02-26 16:30:10 +0100, Magnus Lie Hetland said: It's documented here... http://www.digitalmars.com/d/2.0/phobos/std_cover.html ... but I can't find it in the Phobos source. (Also, I can't import it -- which is perhaps the most pressing issue :) It's just that I'm using rdmd (for convenience), but then I don't know where any coverage reports end up (unless I examine the path to the generated executable), so I thought I'd specify where I wanted them... Seems the specific problem isn't really a problem -- rdmd with -conv places the files in the right directory anyway :) -- Magnus Lie Hetland http://hetland.org
Is std.cover deprecated or gone?
It's documented here... http://www.digitalmars.com/d/2.0/phobos/std_cover.html ... but I can't find it in the Phobos source. (Also, I can't import it -- which is perhaps the most pressing issue :) It's just that I'm using rdmd (for convenience), but then I don't know where any coverage reports end up (unless I examine the path to the generated executable), so I thought I'd specify where I wanted them... -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-26 15:20:19 +0100, David Nadlinger said: On 2/26/11 1:15 PM, Jonathan M Davis wrote: [...] And from a perfectly practical standpoint, as soon as your code ends up in a library, assertions are generally useless anyway,[...] I don't quite think asserts are useless in libraries. If you need to care about performance in a library, you hit cases quite frequently where sanity-checking the input would be too expensive to be done in release mode, and thus you can't specify behavior on invalid input as part of your API using exceptions. Nevertheless, it is still useful to people using your library to get notified when they are messing something up as early as possible in debug mode, which is precisely what asserts are made for, at least in my opinion. But that would only work if they had access to the source, or a version not compiled in release mode, right? Hmm. This is also related to what Jonathan said about programming by contract -- and only using in-clauses (for example) when you also control the calling code. I guess what you're saying could be an argument in the other direction: that even though they certainly shouldn't be considered part of the public API (beyond documenting what would be input causing undefined behavior), they *could* be useful in a library that a client could use in debug mode, because it gives them some extra tests for their own code, "for free". They can test that their own code is using your code correctly. That sounds quite in line with programming by contract to me ... but then, again, I'm a reall n00b on the subject :) -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-26 13:15:58 +0100, Jonathan M Davis said: On Saturday 26 February 2011 03:24:15 Magnus Lie Hetland wrote: OK. I had the impression that using assert() in contracts was standard, also for API functions. I thought contracts fulfilled a similar sort of function to assert(), in that they're removed in release code -- as opposed to enforce(), for example...? I'm guessing that if I released a binary version of a library, I wouldn't leave the contracts in? Or perhaps I would (but, as you say, with exceptions)? Depends on the situation, perhaps? What kind of exceptions would be most relevant to indicate a contract failure (if the contracts are made part of the API)? Well, the biggest problem with using assertions to verify input to a function is that if you distribute your code as a library, odds are it will be in release mode, and then there won't be any assertions in it. [snip lots of stuff] After reading your response, I first made lots of comments, but it's all a bit redundant. My summary is: - You're (at times) talking about preconditions as a general concept, and that for public APIs, they should be enforced using exceptions. - I've only been talking about the *language feature* of preconditions, i.e., in-clauses. - We're both clear on that preconditions and asserts disappear in release mode, and that the two belong together, as part of your test scaffolding (and not as part of your public API). Sound about right? [snip] Regardless of that, however, assertions should only be used when testing the internal logic of your program. If code from other libraries or any other code which you wouldn't be looking to test calls your function, then don't use an assertion to verify pre-conditions. If you're using assertions, you're testing that the caller is correct. You're verifying that the caller is not violating your contract, but you're _not_ guaranteeing that the function will fail if they violate the contract (since assertions can go away). A very clarifying way of putting it, indeed. As for my "testing the test code" intention, I guess (as I said) I actually *did* want to test the test. Not, perhaps, that it was correct (as discussed, it should be really simple), but to see it fail at least once -- a basic principle of test-driven programming. But I'll find other ways of doing that -- for example deliberately making the precondition slightly wrong at first :) The test for the contract is therefore _not_ part of the API. With Exceptions it _is_. Right. So, what it really comes down to is whether you looking to test the code which calls your function and are therefore willing to have that code give you bad input and let your function process it anyway (when assertions aren't compiled in) and you therefore use assertions, _or_ you're looking to guarantee that your function does _not_ continue if the contract is violated, and you want to _always_ error out - in which case you use Exceptions. Yep. All in all, a very useful clarification for me. As a side note: Why isn't there a release-version of the contract mechanisms? I would've thought that contracts would be even more useful between different programmers, than just between you and yourself...?-) That is, wouldn't the same kind of mechanism be useful for *exactly* the kind of exception-based input checking that you're describing as the alternative to contracts+asserts? I mean, the reason to remove preconditions and asserts is primarily performance and not semantics (although it certainly affects semantics, as you've pointed out)? We have enforce() as the alternative to assert(); why no alternative to in/out and invariants? [snip] And if you're using unit tests to test those, you're testing test code. Sure. I've already accepted this :) [snip] Still, if you start testing test code, at what point does it make sense to stop? Hm. Maybe I should write a test that tests itself?-) More seriously: your points are well taken. I still have a vague feeling that in-clauses are a bit different from out-closes, invariants and plain unit tests when it comes to the "fail first" approach to test-driven programming. A precondition won't fail because your code isn't yet functional -- it will only fail if you've actively written *wrong* code. But I guess that's just how it is :) Complicated tests of _any_ kind are a bit dangerous. [snip] Hm. True. Thanks for lots of useful input! (Still curious about the hypothetical "public API contract" functionality, though, and why it's non-existent.) -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-26 01:20:49 +0100, Jonathan M Davis said: So, using such assertions makes good sense when you control both the caller and the callee and it's something that should never happen. Yeah, in my case that's what's going on. I'll only be using the contracts during testing anyway, and remove them with -release in the code that's actually to be used. (The code is part of some benchmarking experiments, so I'd rather not have any kind of checking like that when running those.) However, if you don't necessarily control the caller or if it's something that _could_ happen at runtime (even if it shouldn't), then an exception makes a lot more sense. OK. I had the impression that using assert() in contracts was standard, also for API functions. I thought contracts fulfilled a similar sort of function to assert(), in that they're removed in release code -- as opposed to enforce(), for example...? I'm guessing that if I released a binary version of a library, I wouldn't leave the contracts in? Or perhaps I would (but, as you say, with exceptions)? Depends on the situation, perhaps? What kind of exceptions would be most relevant to indicate a contract failure (if the contracts are made part of the API)? I tend to view exceptions as part of the API and think that they should be tested. Assertions, on the other hand, aren't really part of the API, since they go away in release mode, and I therefore view them as test code. They're verifying that your logic is correct. Exactly. The same, of course, applies to contracts -- which is why I'm a bit confused by your suggestion to use exceptions in them. Or perhaps I'm misreading you completely, and you're only suggesting that I use code paths that throw exceptions in the function body itself, e.g., with enforce(foo, exception) (which would make sense to me)? So, on some level, it is indeed a stylistic thing, but where you choose to use exceptions and where you choose to use assertions can have a big effect on code that uses your code. Sure thing. It just seems to me that contracts and assertions go well together, and have the same function, of testing your program logic? I guess the driving force of my original query was the old "first, see your test fail" idea of test-driven programming. If I just slap a precondition on some code, it won't fail because things aren't implemented properly yet (as a normal unit test would) -- I'd actively have to implement a call to it *improperly*. It just seemed naturally to me to do that as part of the test code, rather than a one-off thing in the main code. However, I could always add a call to my unit test, run it, and see it crash -- and then comment it out. Doesn't seem like the prettiest way to handle things, but it's OK, I guess together with the idea of making the contracts super-simple (and to test any functionality they use separately). [snip] I guess the conclusion will be that I'll focus on keeping my preconditions really simple. (And any utility functions I use in them can then get unit tests of their own instead ;) That's probably a good way to handle it . OK, good :) -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-25 20:04:10 +0100, Jonathan M Davis said: On Friday, February 25, 2011 07:30:50 Magnus Lie Hetland wrote: Or, more generally, how do you test asserts (which is what I'm using in my preconditions etc.)? As far as I can see, collectException() won't collect errors, which is what assert() throws -- so what's the standard way of writing unit tests for preconditions that use assert? (I.e., test that they will, in fact, throw when you break them.) I think that the reality of the matter is the most of the time people _don't_ check them. And on some level, it doesn't make sense to. It's kind of like asking how people test their unit tests. Unit tests are already testing code. Do you want to be testing them on top of that? And if you do, do you test _that_ code? Where do you stop? I guess so. But you could say the same thing about other cases where you throw an exception when you detect that something is wrong -- but those are normally tested, right? Also, the difference here is that the precondition is written as a general "test", whereas my actual test would have specific cases. For example, I have a test that checks that I don't add the same object twice to some structure, and the check involves some traversal -- code that could potentially be wrong. I wanted to make sure that it wasn't by explicitly adding the same object twice -- code (i.e., my unit test) that most likely could not be wrong. But I do see your point. [snip] And testing post-conditions and invariants in the manner that you're trying to do borders on impossible. What are you going to do, repeat the post-condition or invariant test on the result of the function or on the state of the object that the function was called on after the function was called? That's just doing the test twice. Right. You might as well just re-read the post-conditions and invariants to make sure that you wrote them correctly. I do see value in testing pre-conditions if you're using exceptions rather than assertions (which means that you're not use in blocks). In that case, you're testing the API to make sure that it does what it's supposed to do. But if you're dealing with assertions, then it's really test code as opposed to API code, and I don't see the same value in testing that. You'd just be testing test code. OK. For the practical reason, I refer you to my explanation above. But I guess it's a style issue -- and I'm fine with not testing these things, by all means. [snip] Those changes _do_ make it so that you can use collectException to collect an Error (though it defaults to catching Exceptions only), but they also include assertThrown and assertNotThrown which effectively assert that the Exception or Error that you expected to be thrown (or not) from a particular expression or function call was indeed thrown (or not). So, you _can_ use that with AssertError to verify your pre-conditions. OK, thanks. However, I would point out that catching Errors is generally a _bad_ idea. [snip lots of useful stuff] Thanks for educating me :D I guess the conclusion will be that I'll focus on keeping my preconditions really simple. (And any utility functions I use in them can then get unit tests of their own instead ;) -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-25 17:48:54 +0100, spir said: On 02/25/2011 04:30 PM, Magnus Lie Hetland wrote: Or, more generally, how do you test asserts (which is what I'm using in my preconditions etc.)? As far as I can see, collectException() won't collect errors, which is what assert() throws -- so what's the standard way of writing unit tests for preconditions that use assert? (I.e., test that they will, in fact, throw when you break them.) See the page on DbC: http://www.digitalmars.com/d/2.0/dbc.html. Denis Hm. I'm not sure how this answers my question. I know how pre/postconditions etc. work -- I was asking for how to test them in a unit test (i.e., ensure that they'll kick in if you provide faulty intput, for example). Maybe I'm missing something in the doc you referred me to? -- Magnus Lie Hetland http://hetland.org
Re: How do you test pre-/post-conditions and invariants?
On 2011-02-25 19:18:40 +0100, Jesse Phillips said: There has been talk of a std.unittest that would help with this, but for now: unittest { try { callMeWrong(wrong); assert(0); catch(AssertError e) { } } } Ah. I used something like... auto thrown = 0; try foo() catch (AssertError) thrown++; ... assert(thrown == k); I guess I could wrap it up a bit, or something. -- Magnus Lie Hetland http://hetland.org
How do you test pre-/post-conditions and invariants?
Or, more generally, how do you test asserts (which is what I'm using in my preconditions etc.)? As far as I can see, collectException() won't collect errors, which is what assert() throws -- so what's the standard way of writing unit tests for preconditions that use assert? (I.e., test that they will, in fact, throw when you break them.) -- Magnus Lie Hetland http://hetland.org
Re: rdmd problems (OS X Leopard, DMD 2.052)
On 2011-02-21 15:17:44 +0100, Jacob Carlborg said: On 2011-02-21 14:16, Lars T. Kyllingstad wrote: 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. Let me first clarify: By "nothing happens", I really mean that. When I supply --shebang, the code isn't compiled, and nothing is run. Running the script becomes a no-op. As for your example: The switches to rdmd *don't* appear in args for me. So for example, if I have #!/path/to/rdmd -unittest ... as the shebang line, rdmd finds and passes the -unittest switch to dmd (my unit tests work). I get no problems when I add more switches either (i.e., rdmd doesn't complain). But, as far as I can see, none of these end up in args. (Or are we talking about different things here?) Instead, args[0] contains the full path to the temporary executable built and run by rdmd, and args[1..$] contain any arguments I supplied when running the script. The fact that --shebang borks the whole execution seems like it must be a bug. As for the rest of the behavior, it seems pretty useful to me, but perhaps OS X-specific? (That would be odd, but who knows...) -- Magnus Lie Hetland http://hetland.org
Re: rdmd problems (OS X Leopard, DMD 2.052)
On 2011-02-22 22:46:41 +0100, Paolo Invernizzi said: Hi Magnus, This is sligthly OT, but... How I loved AnyGui! Haha, cool :D Yeah, too bad the project died. Oh, well -- at least we tried :) It's nice to see you here, in the D bandwagon... Yeah, I've been looking for a more "close to the metal" language to complement Python for a looong time (using C and C++ when I had to -- and sometimes Java or Cython and what-have-you). At the moment I'm hopeful that D might be what I've been looking for. Loving it so far :) (Still using Python, though. Just came out with a new Python book, "Python Algorithms", last fall ;) -- Magnus Lie Hetland http://hetland.org
Re: rdmd problems (OS X Leopard, DMD 2.052)
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? -- Magnus Lie Hetland http://hetland.org
Re: rdmd problems (OS X Leopard, DMD 2.052)
On 2011-02-20 22:42:06 +0100, Nick Sabalausky said: [snip] We used to have occasional breking changes in the language itself (in D2-only), since D2 was the deliberately the "development" branch rather than the "stable" branch that D1 has been, but D2's language spec is pretty much finalized now. I just realized I didn't give a direct answer to your question: I'd say that most minor releases of DMD are *not* backward-incompatible. Thanks for both the thorough and the more direct answer. Very helpful/useful :) -- Magnus Lie Hetland http://hetland.org
Re: rdmd problems (OS X Leopard, DMD 2.052)
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! (Yes, it is 4 months old, and I can do the match: 3 < 4, but this *is* the same as the latest official version just with my patches applied: The latest official commit to rdmd.d was one of my patches (albiet slightly modified, IIRC)) However, the latest version of DMD I used this with was 2.050, so it might still need some updating for 2.052. Hm. Are most minor releases of DMD backward-incompatible? (Sort of a scary prospect to me, at least...) -- Magnus Lie Hetland http://hetland.org
rdmd problems (OS X Leopard, DMD 2.052)
Hi! When I installed DMD 2.051 on my OS X boxen, the rdmd executable didn't work. I saw others have similar problems online, and concluded that it must have been compiled for a more recent version of OS X (Snow Leopard, I guess) without the necessary compatibility flags. I found the rdmd sources online [1] and compiled them myself. (Luckily, the other binaries work just fine.) No problems. Now I'm trying to get DMD 2.052 to work. Same issue with the rdmd executable. I tried to compile the same rdmd.d file with the new compiler/stdlib, but that failed. $ dmd rdmd.d std.contracts has been scheduled for deprecation. Please use std.exception instead. std.date and std.dateparse have been scheduled for deprecation. Please use std.datetime instead. rdmd.d(34): Error: std.regexp.split at ./../../src/phobos/std/regexp.d(498) conflicts with std.string.split at ./../../src/phobos/std/string.d(69) rdmd.d(34): Error: function std.regexp.split (string s, RegExp pattern) is not callable using argument types (string) rdmd.d(34): Error: expected 3 function arguments, not 1 I'm sure I can fix this myself -- but I'm guessing there must be a more recent version of the rdmd sources somewhere, assuming that the binary in the distribution was compiled with dmd 2.052...? The version in the trunk at dsource.org seems to be three months old... For now I just compiled the rdmd.d from dsource.org with dmd 2.051, and use that with dmd 2.052. As rdmd is basically an independent entity, I guess that should work well, but this isn't exactly user-friendly (i.e., having to replace one of the binaries in the distro with one compiled with an older compiler, using sources obtained elsewhere... :->). Not sure if I'm missing The Way to Do It[tm], or if perhaps I should submit an issue about this? [1] http://www.digitalmars.com/d/2.0/rdmd.html -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 16:41:33 +0100, Simen kjaeraas said: That certainly makes sense. I just got thrown off by the example in std.algorithm: uint hashFun(string) { ... expensive computation ... } string[] array = ...; // Sort strings by hash, slow sort!("hashFun(a) < hashFun(b)")(array); The only way this could work would be if hashFun was available to the sort template, I guess...? Nope, still std.functional. That's where the string is mixin'ed. Right. Given the example, there's no way to tell that sort is implemented using std.functional, so really meant whichever function is actually using the string ;) But, yeah, I understand how it works. Thanks. But thanks for noting that, I've filed it as issue #5513. Good. -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 16:09:22 +0100, Simen kjaeraas said: Magnus Lie Hetland wrote: Sort of related (though perhaps only remotely) is the following, which won't compile (Error: static assert "Bad unary function: f(a) for type int"): Not related. unaryFun and binaryFun are simply glorified string mixins, and thus can only access functions that are available in the modules where they are mixed in. That would be std.functional. Because of that, local functions may not be used as string arguments for *naryFun. That certainly makes sense. I just got thrown off by the example in std.algorithm: uint hashFun(string) { ... expensive computation ... } string[] array = ...; // Sort strings by hash, slow sort!("hashFun(a) < hashFun(b)")(array); The only way this could work would be if hashFun was available to the sort template, I guess...? -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 16:00:16 +0100, Magnus Lie Hetland said: import std.functional, std.stdio; int f(int x) {return x;} void main() { alias unaryFun!("f(a)") g; writeln(g(3)); } Just to be clear -- I realize I could just have used unaryFun!f here (or just f, for that matter). The usage case was actually currying. I used "f(x,a)" as a compile-time argument to the kind of template that we discussed earlier. And the reason I tried that was that this didn't work either: import std.functional, std.stdio; int f(int x, int y) {return x;} void main() { alias unaryFun!(curry(f, 2)) g; writeln(g(3)); } At that point, the only thing that worked was using a lambda. And, as I pointed out, with the nested templates, that didn't work either. Seems like the language (or the stdlib) is resisting my efforts at every turn here. Perhaps I should just write out those for-loops redundantly, rather than using templates ;) -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 12:37:05 +0100, Simen kjaeraas said: Magnus Lie Hetland wrote: Hm. Just to make sure this *is* a bug, and I'm not just being a dumbass ... this is a tiny program that illustrates the problem (i.e., gives the error above). Perhaps the use of a local function here really is prohibited...? Maybe it is. It really shouldn't be, though. If this is not a bug, then Walter has a bug for not accepting this as a bug. :p Hehe :) Sort of related (though perhaps only remotely) is the following, which won't compile (Error: static assert "Bad unary function: f(a) for type int"): import std.functional, std.stdio; int f(int x) {return x;} void main() { alias unaryFun!("f(a)") g; writeln(g(3)); } It may not be related -- but I've been trying to use the string representation instead of lambda in some places, and I thought maybe a similar name lookup problem may be present in the unaryFun template? (The detauls of the implementation are a bit beyond me at the moment...) Maybe there's an unstated restriction against using functions in the unaryFun string parameter (at least I couldn't find it in the docs) -- but ... there is the following example in the docs for std.algorithms: sort!("hashFun(a) < hashFun(b)")(array); So it would seem like this *should* work? -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 10:12:44 +0100, Magnus Lie Hetland said: On 2011-01-31 19:46:53 +0100, Simen kjaeraas said: Magnus Lie Hetland wrote: Hm. Using code quite similar to you, supplying a lambda in the second aliasing, I get this error: something.d(93): Error: template instance cannot use local '__dgliteral2(__T3)' as parameter to non-global template optArg(alias fun) [snip] This is a bug. Please report it. Ah -- OK. Will do. Hm. Just to make sure this *is* a bug, and I'm not just being a dumbass ... this is a tiny program that illustrates the problem (i.e., gives the error above). Perhaps the use of a local function here really is prohibited...? template A(int op) { template A(alias fun) { auto A(T)(T x) { return 0; } } } alias A!0 B; int gun() { return 0; } void main() { int fun() {return 0;} // alias B!((){return 0;}) C; // Won't compile // alias B!(fun) C; // Won't compile alias B!(gun) C; // Works } -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 10:49:23 +0100, bearophile said: Magnus Lie Hetland: Saw your post on digitalmars.D now, about the currying of templates (i.e., the main topic here). I guess perhaps that was what you were talking about? Tuple unpacking syntax and template currying are two different things. Yes, certainly. That was the point of this post -- that I misunderstood what you were talking about in the original post (where you said "this topic" right after my tuple unpacking paragraph) :) -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-02-01 10:11:53 +0100, Magnus Lie Hetland said: On 2011-01-31 22:21:40 +0100, bearophile said: Magnus Lie Hetland: [snip] I'm accustomed to is the ability to assign to multiple variables, such as arg, val = minArg(...) (Yeah, I'm a Python guy... ;) I will eventually add a detailed enhancement request on this topic. Great! I think this is really useful -- also for swapping things around (a, b = b, a). For multiple return values it makes a huge difference, IMO. Saw your post on digitalmars.D now, about the currying of templates (i.e., the main topic here). I guess perhaps that was what you were talking about? That would certainly be great, too :) -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-01-31 19:46:53 +0100, Simen kjaeraas said: Magnus Lie Hetland wrote: Hm. Using code quite similar to you, supplying a lambda in the second aliasing, I get this error: something.d(93): Error: template instance cannot use local '__dgliteral2(__T3)' as parameter to non-global template optArg(alias fun) [snip] This is a bug. Please report it. Ah -- OK. Will do. -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-01-31 22:21:40 +0100, bearophile said: Magnus Lie Hetland: [snip] I'm accustomed to is the ability to assign to multiple variables, such as arg, val = minArg(...) (Yeah, I'm a Python guy... ;) I will eventually add a detailed enhancement request on this topic. Great! I think this is really useful -- also for swapping things around (a, b = b, a). For multiple return values it makes a huge difference, IMO. -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
Hm. Using code quite similar to you, supplying a lambda in the second aliasing, I get this error: something.d(93): Error: template instance cannot use local '__dgliteral2(__T3)' as parameter to non-global template optArg(alias fun) It seems it's explicitly objecting to what I want it to do... Using optArg!"a", for example, works just fine -- but the whole point was to include some local state. Using local functions worked (I think...?) when I had a global template. It seems D's compile-time computation system is less straightforward than I thought :) -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-01-31 15:50:41 +0100, Simen kjaeraas said: You might want to try more from dranges - the reftuple: _(arg,val) = minArg(...); [snip] This is also a possible implementation (coded in about 5 minutes, gives no nice error messages, but it seems to work :p ): Thanks :) Yeah. D has the nice Eponymous Template Trick, but it sadly only works for one level. :( Right :-/ So you have to test for every single element of the range? Yup. If so, I think this works: Thanks. Hm. The nesting does seem similar to how I did it, but I guess there must be some crucial difference ;-) At the moment, I'm using a mixing to create the min and max templates (as rather large strings). Probably not ideal. Thanks! -- Magnus Lie Hetland http://hetland.org
Re: Partially instantiating templates?
On 2011-01-31 12:55:07 +0100, Simen kjaeraas said: ElementType!Range minArg( alias fun, Range )( Range range, out ReturnType!fun ) { ... } Aaaah. I guess I tried ElementType(Range), forgetting to make it a compile-time parameter. Thanks. (Hadn't seen ReturnType; makes sense :) Might I also ask why you use an out parameter instead of a tuple return? Well... I had a tuple return at first, but one of the advantages of returning multiple values that I'm accustomed to is the ability to assign to multiple variables, such as arg, val = minArg(...) (Yeah, I'm a Python guy... ;) As far as I can see, you can't do that here? Using result[0] and result[1] or the like, or assigning separately to two variables just seemed more cumbersome. Then again, I could use a tuple with named members, I guess. In your opinion, what would be the prettiest (in D terms) way of doing this? [snip] D currently does not support template currying to any good degree. OK. Well, I guess I don't really need it. Still trying to get a feel for what's "normal" D :) However, there is at least one library out there that does that for you: http://www.dsource.org/projects/dranges In the file templates.d, there is the template CurryTemplate, which rewrites a template to a set of nested templates. This would allow you to partially instantiate a template, and add more parameters as you go. I see. I actually don't mind writing nested templates myself -- but for some reason I couldn't get them to work properly. (D kept complaining about declarations vs instances, and the like; I guess I'll have a look at how dranges does it.) I've been able to make either one of these two pieces of functionality work with some twiddling and nesting (i.e., *either* instantiating optArg into minArg/maxArg, *or* instantiating explicitly defined minArg/maxArg into specialized functions) but combining them has so far eluded me (unless I start fiddling with strinc constants and mixin(), which seems excessively hacky for such a simple thing). dranges' templates.CurryTemplate should take care of some of your problems. Not sure if it will fix them all. OK, thanks. By the way, if you have suggestions for other more "D-like" ways of encapsulating this functionality (basically a linear scan for an element that yields a max/min value for a given expression), I'd be interested to hear that too. The best way to solve a problem is often to rephrase it :) -- Magnus Lie Hetland http://hetland.org
Partially instantiating templates?
I'm building a function (or template or whatever, really) that is related to map and minPos in std.algorithm. Basically, it's the standard mathematical argmin, except that it also returns min. It looks something like this: auto minArg(alias fun, Range, T)(Range range, out T minVal) { ... } Already there may be issues -- the return type should be ElementType(range) and T should be the return type of fun ... but it works. (Suggestions on these issues are welcome, but that's not really the main point here.) The thing is, because I'm also returning the actual value, I'd rather not use the strategy of std.algorithm.minPos, which asks you to use an inverted function to get maxPos; instead, I'd like an explicit maxArg function. My idea was to have a common, more general optArg, which took an operator ("<" or ">") as a compile-time argument. Then I could do something like alias optArg!"<" minArg; alias optArg!">" maxArg; Then, at some *later* time, I might want to do something like: alias maxArg!((v) {return dist(u,v);}) farthest; (By the way: For some reason, I'm not allowed to use curry(dist,u) instead of the lambda here, it seems. Any insights on that? Would have been nice to use "d(u,a)" as well -- as I do use unaryFunc on the fun argument. That doesn't work either, though...) I've been able to make either one of these two pieces of functionality work with some twiddling and nesting (i.e., *either* instantiating optArg into minArg/maxArg, *or* instantiating explicitly defined minArg/maxArg into specialized functions) but combining them has so far eluded me (unless I start fiddling with strinc constants and mixin(), which seems excessively hacky for such a simple thing). Any ideas/suggestions? I'm sure I'm missing something obvious ... (Perhaps even existing functionality for minArg/maxArg -- although the general question still stands.) -- Magnus Lie Hetland http://hetland.org