"H. S. Teoh" <hst...@quickfur.ath.cx> wrote in message news:mailman.949.1332305140.4860.digitalmar...@puremagic.com... > > Yeah, AA's with int keys are like arrays enhanced with O(1) > insertion/removal and sparse storage (if you have very large indices, > e.g.). :-) You can even have (pseudo) linear access if you iterate keys > from 0 to $.
Exactly. > For example, it lets you accept keys/values that are not strictly the > AA's key/value type, but can be implicitly converted to them. It lets > you return keys and values without needing the ugly typeinfo and void* > casts that are necessary in aaA.d. This in turn lets you mark many AA > methods as pure, and almost all as @safe or @trusted. It lets you > cleanly interoperate with types that define opAssign (currently aaA.d > does a blind binary copy of data from key/value pointers, which leads to > potential bugs when the data has subobjects.) > > It also makes it *much* easier to fix many existing AA bugs in the > bugtracker. So far, I have working unittests for the following issues: > 3824, 3825, 4337, 4463, 5685, 6210, 7512, 7512, 7602, 7632, 7665, 7665, > 7704. I haven't looked through all AA-related issues yet; this list may > very well grow. :-) To fix these in the current aaA.d implementation can > be rather tricky, and quite possibly requires compiler changes. > I see. Cool stuff. > Better yet, I thought of a way of making AA's instantiable at > compile-time via CTFE and mixins: this will let you write AA literals > that can be evaluated at compile-time and have them turn into object > code directly without needing runtime initialization. > Ah! Now *that's* fucking awesome! That limitation has kinda stuck out as an odd, annoying wart. > >> And even *that* still doesn't work if you don't catch *every* >> exception (and then rethrow the ones you don't care about? Ick!). > > Actually, you can catch "..." and it will catch *everything*. And I > believe a single "throw;" will rethrow whatever it is you caught. > I see. It has been awhile since I've been in the C++ loop. > >> I've seen C++ programmers swear off exceptions because of this, and I >> can't blame them at all. Exception systems *need* a finally. > > Yeah. "catch(...)" sorta works, but it's very ugly. And while being able > to throw *anything* at all is nice (I'm guilty of writing code that > throws char*, for example), not being able to make *any* assumptions at > all about what you caught (e.g., no common exception superclass with > some useful methods, like .msg) is, shall we say, practically useless in > a large enough project? > Boy, it really has been awhile. I knew you could throw any class object in C++, but I thought that was all. Haxe lets you throw literally anything, even Int, and I found that to be more of a problem than a feature (In very much the same way as VB's ability to change the lower bound of an array: It gains little and just means you have to remember to do the rediculous "UBound(arr) - LBound(arr)".) Just have a proper Exception class and nothing else should be throwable (D's "Error" notwithstanding). > (Actually, the lack of .msg was what drove me to throw char*. Obviously > checking return codes for every lousy function I call is out of the > question, but so is throwing error codes that come from different > subsystems, since you've no way of telling which error code scheme to > use to look up the error. So I said to myself, why not throw a string > that actually tells you what the error is? Furthermore, if these strings > were predefined in char arrays that had unique pointer addresses, the > value of the pointer itself serves as a kind of "global error number". > So this worked as a kind of a poor man's error code + message exception > that can be freely thrown around without problems That is an interesting work around. > the reason I shied > away from throwing class objects in the first place was because early > implementations of C++ had problems that sometimes caused pointer bugs > and all kinds of nasty side effects when a class object is thrown. Ouch! > > Scope guards rule. Ironically, D's GC mostly alleviates the need for > scope guards. :-) They're still immensely useful when you acquire > resources that must be cleaned up no matter what happens later. D is the > first and only language I know that got resource cleanup done right. > Cleanups belong with the acquisition code, not dangling somewhere 200 > lines down at the end of the scope, with who knows how many possible > leaks in between due to goto's, exceptions, returns, and who knows what! > I've even come across at least a couple uses of scope guard that aren't strictly related to releasing resources. Actually, I've just been working with both of them today: - Temporarily changing a value: int bar; void foo() { // Change bar temporarily auto saveBar = bar; bar = 777; scope(exit) bar = saveBar; [...do anything here...] } - Timing a section of code. I saw this trick in someone else's code once, loved it, and made a helper tool out of it: https://bitbucket.org/Abscissa/semitwistdtools/src/4455e019cd95/src/semitwist/util/mixins.d#cl-643 It's a string mixin that, after features and hygenic issues and such, basically boils down to mixing in this psuedo-code: if(verbose) { write(customMessage, "..."); // no newline stdout.flush(); startTimer(); // Using the awesome new std.datetime } scope(exit) if(verbose) writeln(timerInMilliseconds(), "ms"); > > CTFE even makes it possible to express what many recursive templates > express, in pure imperative style. I mean, you can't get any better than > this: > > int factorial(int n) { > int result = 1; > while (n>1) { > result *= n; > result--; > } > return result; > } > enum x = factorial(12); // compile-time computation > int y = factorial(12); // runtime computation > > In C++, you'd have to use recursive templates that are extremely > difficult to read and write beyond the simplest of functions. > Yup exactly. It's Haskell with bad syntax and compile times. Not only that, but even something as trivial as "if" has to be built out of pure-fp primitives in C++-template-land, whereas D just has: "static if...done!" Of course, to C++'s credit, its templates (AIUI) weren't really designed for metaprogramming, just for generics. The metaprogramming was just a happy accident (At least that's my understanding, maybe I'm wrong...) > >> With C++'s templates, it would appear that you have to use recursion >> and helper templates for damn near anything. > [...] > > Not to mention the horrible, horrible, syntax that comes with recursive > templates. My previous manager used to tell me that as soon as he sees > nested templates deeper than 2 levels, his eyes start glazing over, and > it all becomes just arcane black magic. > Yea. Even a "simpler" use of C++'s templates can feel like staring into the depths of hell: Ever see a loop over a collection using STL iterators? Sheesh. I like the idea behind the STL, but with syntax like that I'd rather use the old "for(int i=0; i<theEnd; i++)". Gimme a proper foreach anyday. Come to think of it, foreach probably fits the bill for the OP: For people who came from C/C++ like I did, it can seem like a relatively trivial sugar over "for(int i=0; i<theEnd; i++)". But it makes such a difference to just not have to constantly deal with those minute mechanics. > -- > Which is worse: ignorance or apathy? Who knows? Who cares? -- Erich > Schubert lol :) Now that's without a doubt one of my favorites.