State of OpenGL bindings
Hi, all. If I wanted to create an OpenGL project in D, what would be supported by current bindings? Are the bindings out-of-date compared to the C library versions or are they the same? Thank you. -- Atenciosamente / Sincerely, Guilherme Prá Vieira http://www.linkedin.com/in/n2liquid http://www.linkedin.com/in/n2liquid http://www.linkedin.com/in/n2liquid
Re: Thin delegate adapter
On Thu, Jan 13, 2011 at 5:30 AM, Dmitry Olshansky dmitry.o...@gmail.comwrote: On 13.01.2011 2:16, Guilherme Vieira wrote: No sh*t..?! @__@ That's so cool! But is it smart enough to know the stack frame doesn't need to go to heap in this case? (since it returns a heap object referecing another heap object, i.e. can it untangle `b' from the stack?) Ehm, it can optimize certain cases but for the moment it doesn't. Still, it needs to store b somewhere, right? and delegate is 2 pointers in fact, so b should go on heap anyway. So it narrows down to if it can save only parts of the stack frame ... Since it only uses something the size of a pointer (`b'), it might as well do some trickery and use `b' as `this' and turn the delegate into (Switch.State state) { this.toggled = cast(bool)(state); } (or something of similar effect). -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Thin delegate adapter
Hi, I'm wondering if a delegate adapter template like isn't handy for Phobos (it may be especially useful for std.signal): class Switch { enum State { ON, OFF } void trigger() { switch (mState) { case State.ON: mState = State.OFF; break; case State.OFF: mState = State.ON; break; default: break; } if (watch !is null) watch(mState); } void delegate(State s) watch; private State mState; } class ToggleButton { @property toggled(bool toggled) { writeln(ToggleButton.toggled(, toggled, )); } } void main() { scope s = new Switch(); scope b = new ToggleButton(); s.watch = b.toggled; // error: invalid conversion s.watch = adapt!(obj.toggled = cast(bool)(a), Switch.State)(b); s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } Yes, it urges to be polished. Particularly, it doesn't support multiple arguments. I also wanted to place the argument type tuple somwhere else (actually wanted to hide it completely, but I think that's not possible). Feedback? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Thin delegate adapter
On Wed, Jan 12, 2011 at 10:41 AM, Guilherme Vieira n2.nitro...@gmail.comwrote: Hi, I'm wondering if a delegate adapter template like isn't handy for Phobos (it may be especially useful for std.signal): class Switch { enum State { ON, OFF } void trigger() { switch (mState) { case State.ON: mState = State.OFF; break; case State.OFF: mState = State.ON; break; default: break; } if (watch !is null) watch(mState); } void delegate(State s) watch; private State mState; } class ToggleButton { @property toggled(bool toggled) { writeln(ToggleButton.toggled(, toggled, )); } } void main() { scope s = new Switch(); scope b = new ToggleButton(); s.watch = b.toggled; // error: invalid conversion s.watch = adapt!(obj.toggled = cast(bool)(a), Switch.State)(b); s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } Yes, it urges to be polished. Particularly, it doesn't support multiple arguments. I also wanted to place the argument type tuple somwhere else (actually wanted to hide it completely, but I think that's not possible). Feedback? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira Oops, missed the template itself: template adapt(alias fun, Arg) { auto adapt(Object)(Object obj) { auto adaptImpl = new AdaptImpl!(fun, Object)(obj); return adaptImpl.opCall!(Arg); } } class AdaptImpl(alias fun, Object) { this(Object obj) { this.obj = obj; } auto opCall(Arg)(Arg a) { return binaryFun!(fun, a, obj)(a, obj); } private Object obj; } -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Thin delegate adapter
Ah, I totally missed that. But what if `s' went out of the scope and the scope ended? Wouldn't the scope reference (the one containing `b') be lost and cause memory corruption? E.g.: Switch make_switch() { auto s = new Switch(); auto b = new ToggleButton(); s.watch = (Switch.State state) { b.toggled = cast(bool)(state); }; return s; } -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira On Wed, Jan 12, 2011 at 10:57 AM, Dmitry Olshansky dmitry.o...@gmail.comwrote: On 12.01.2011 15:41, Guilherme Vieira wrote: Hi, I'm wondering if a delegate adapter template like isn't handy for Phobos (it may be especially useful for std.signal): class Switch { enum State { ON, OFF } void trigger() { switch (mState) { case State.ON: mState = State..OFF; break; case State.OFF: mState = State.ON; break; default: break; } if (watch !is null) watch(mState); } void delegate(State s) watch; private State mState; } class ToggleButton { @property toggled(bool toggled) { writeln(ToggleButton.toggled(, toggled, )); } } void main() { scope s = new Switch(); scope b = new ToggleButton(); s.watch = b.toggled; // error: invalid conversion s.watch = adapt!(obj.toggled = cast(bool)(a), Switch.State)(b); s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } Yes, it urges to be polished. Particularly, it doesn't support multiple arguments. I also wanted to place the argument type tuple somwhere else (actually wanted to hide it completely, but I think that's not possible). Feedback? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira How is it better then built-in language feature? This works just fine: void main() { //they can't be scope and compiler enforces this (+ scope is deprecated) //actually, the orignal code is unsafe - what hapens if adapted delegate escapes current scope? auto s = new Switch(); auto b = new ToggleButton(); s.watch = (Switch.State a){ b.toggled = cast(bool)a; }; s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } -- Dmitry Olshansky
Re: Thin delegate adapter
No sh*t..?! @__@ That's so cool! But is it smart enough to know the stack frame doesn't need to go to heap in this case? (since it returns a heap object referecing another heap object, i.e. can it untangle `b' from the stack?) -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira On Wed, Jan 12, 2011 at 11:49 AM, Dmitry Olshansky dmitry.o...@gmail.comwrote: On 12.01.2011 16:07, Guilherme Vieira wrote: Ah, I totally missed that. But what if `s' went out of the scope and the scope ended? Wouldn't the scope reference (the one containing `b') be lost and cause memory corruption? E.g.: Switch make_switch() { auto s = new Switch(); auto b = new ToggleButton(); s.watch = (Switch.State state) { b.toggled = cast(bool)(state); }; return s; } That's the main point of built-in delegates - the compiler detects them and places the enclosing stack frame on heap, so it's all sort of cool magic that just works :) -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira On Wed, Jan 12, 2011 at 10:57 AM, Dmitry Olshansky dmitry.o...@gmail.commailto: dmitry.o...@gmail.com wrote: On 12.01.2011 15:41, Guilherme Vieira wrote: Hi, I'm wondering if a delegate adapter template like isn't handy for Phobos (it may be especially useful for std.signal): class Switch { enum State { ON, OFF } void trigger() { switch (mState) { case State.ON: mState = State..OFF; break; case State.OFF: mState = State.ON; break; default: break; } if (watch !is null) watch(mState); } void delegate(State s) watch; private State mState; } class ToggleButton { @property toggled(bool toggled) { writeln(ToggleButton.toggled(, toggled, )); } } void main() { scope s = new Switch(); scope b = new ToggleButton(); s.watch = b.toggled; // error: invalid conversion s.watch = adapt!(obj.toggled = cast(bool)(a), Switch.State)(b); s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } Yes, it urges to be polished. Particularly, it doesn't support multiple arguments. I also wanted to place the argument type tuple somwhere else (actually wanted to hide it completely, but I think that's not possible). Feedback? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira How is it better then built-in language feature? This works just fine: void main() { //they can't be scope and compiler enforces this (+ scope is deprecated) //actually, the orignal code is unsafe - what hapens if adapted delegate escapes current scope? auto s = new Switch(); auto b = new ToggleButton(); s.watch = (Switch.State a){ b.toggled = cast(bool)a; }; s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` s.trigger(); // prints `ToggleButton.toggled(true)` s.trigger(); // prints `ToggleButton.toggled(false)` } -- Dmitry Olshansky -- Dmitry Olshansky
Struct constructors callable twice?
I've found this behavior while toying with opCall() in a struct: import std.stdio; struct Struct { this(int value) { writeln(Struct.this(, value, )); } ~this() { writeln(Struct.~this()); } } void main() { Struct s = Struct(1); // prints `Struct.this(1)` s(2); // prints `Struct.this(2)` s(3); // prints `Struct.this(3)` } // prints `Struct.~this()` Notice how the destructor is only called once. If there was an opCall defined for Struct, its reconstruction would shadow it. It certainly looks like a bug to me, but since I'm sure of nothing in D I decided to post it here. Is it really a bug? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Struct constructors callable twice?
Yes, it was meddling with that bug that I cooked this one. I think Adam got it right: There should be no problem between an instance opCall and a constructor. In your case, it seems, a static opCall was clashing with the constructor. But it turns out a non-static opCall clashes with a constructor that AFAIK shouldn't even be there (see my initial post). -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira On Wed, Jan 12, 2011 at 10:12 AM, bearophile bearophileh...@lycos.comwrote: See also: http://d.puremagic.com/issues/show_bug.cgi?id=4053 Bye, bearophile
Re: How to convert Map to array?
It's easier to help if you provide sample code that produces the message. I got that message today and fixed it, I just don't what was the problem. -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira On Mon, Jan 10, 2011 at 1:25 AM, Sean Eskapp eatingstap...@gmail.comwrote: I'm trying to use the array() function in std.array to convert a transformed array using map (std.algorithm) back to a dynamic array, from a Map. I keep getting a cryptic error object.except...@c:\Program Files (x86)\D\dmd2\windows\bin\..\..\src\phobos\std\ algorithm.d(426): Cannot reduce an empty range w/o an explicit seed value.. Am I misunderstanding how this is supposed to work?
Named tuple from struct
Is is possible to get a named tuple from a struct type? E.g.: struct S { int foo; string bar; } S s; S.tupleof t; // S.tupleof is a tuple type, as opposed to s.tupleof, // which yields a tuple instance t[0] = 1; t.bar = 2; If not, I think it would be quite useful. Even still, a way to describe tuple types as if it was a struct would also be useful: tuple StructLike { int foo; string bar; } StructLike t; t[0] = 1; t.bar = 2; -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Patterns of Bugs
On Thu, Jan 6, 2011 at 6:25 PM, Robert Clipsham rob...@octarineparrot.comwrote: On 06/01/11 19:38, Walter Bright wrote: http://www.drdobbs.com/blog/archives/2011/01/patterns_of_bug.html (dedicated to bearophile!) Anyone want to post it on reddit? It's too bad there doesn't seem to be an online repository of them. They would make for great research material for programming language designers. Every one you can design out of existence will incrementally improve the productivity of programmers. Perhaps someone here would like to volunteer for this? I guess some kind of moderated bugzilla would do the trick, it'd be awesome to have some table of languages and how many of the types bugs they prevent/kind of prevent as well. If no one else volunteers I guess I could hack something crude together, it would still need people to volunteer bugs for it, as well as sources/proof for each bug (links to changesets/projects that have encountered this issue etc). -- Robert http://octarineparrot.com/ I loved the idea, but I personally dislike Bugzilla and I wonder if it would work for something like that. Anyway a voting system would be mandatory. In any case, isn't there something like this already? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Is this a viable effort? The DRY principle, community-wide
On Tue, Jan 4, 2011 at 11:13 AM, spir denis.s...@gmail.com wrote: On Tue, 4 Jan 2011 02:30:24 -0200 Guilherme Vieira n2.nitro...@gmail.com wrote: At times like this I wish people would really break their code in smaller parts in a way you could really just pick what you want from it. I guess this is a dream generations of programmers, language designers and computer scientist have run after. Say, Lego programming. Bulding bricks which are _really_ autonomous. Maybe there is a flaw in the implicite reasoning behind that vision: as a client, one wants the (library) building blocks they use to be autonomous, right; but at a higher-level the software one is designing is precisely using other software, thus creating a system of dependancies... which makes this new piece of code unusable in an autonomous manner by yet another client who would enjoy reusing it as a brick. The same applies to the (library) bricks: they have to use other building blocks which prevent them to be autonomous. This is how I see the point. And it gets even more unavoidable because of generality. For a brick to have any chance to meet one client's needs it must be as general/abstract as possible. This means for instance abstract away issues of OS idiosyncrasies, actual types, sizes and loads of other annoying aspects, think at how write*, map, or file opening work. To do this, using yet another bunch of tools is often necessary. The more a brick gets general and thus useful, the more chances it has _not_ to be autonomous. I guess. This, to the point that if Phobos (2) would be rewritten from scratch using everywhere D2's newer style (more general/abstract, as I see it), most of its modules would import a load of other modules such as algorithm, contracts, functional, range, possibly type*, traits, variant; which themselves import... I don't logically there can be a solution. I would like to try to define a minimal subset D lib functionality, say the standard toolkit. (I have one for my personal, a dozen elements systematically imported, and most commonly actually used, in every of my modules.) Then, make this a kind of auto-import (à la python) for user code, except if other wise stated; and see if it's enough, overkill, whatever. Then, struggle to make (other) lib modules depend on these toolkit elements, and only and them, as much as possible. (Even when it's not the best design/code solution.) Could such an approach work? Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com Yes, I don't see how could each module not depend on each other, but that's not the point. It would be a hierarchy, after all; there would have to be dependencies. But I don't particularly care if a C++ library depends on Boost, for example. Boost is behemoth, but it is well-modularized (you can really pick just a pretty small subset of it) and, more importantly, it's so widely accepted it's almost a standard library. So who cares? On Tue, Jan 4, 2011 at 9:06 AM, Dmitry Olshansky dmitry.o...@gmail.comwrote: Sounds a lot like std lib. Maybe an incubator project for Phobos? (was discussed sometime ago) Also check scrapple on Dsource. I don't think it could get into Phobos. I think of relatively bigger things, too, such as cross-platform mouse, keyboard and gamepad input library done right to be the definitive way of doing that on D. That just doesn't seem fit for a true standard library, does it? For example, what do you do if you want to create a window just for use with OpenGL in a cross-platform way? You have to write different versions of the window creation procedure for the different systems you're targeting. Or you could use SDL, but if you really just want the window that's a waste. Right? For that particular case GLUT may fit just fine. Or GLAux. I see GLUT solves the problem for OpenGL, but then we get to the granularity point: the input library I told you above also needs a window. To make it depend on GLUT would be stupid. And then we get back to the wheel reinvention problem. The only problem with it : people still can't invent the best way to do something, plus the matter of taste. The best way of doing something is always a subjective matter. But, as usual, one can define rules that, when fully respected, result in something that can be tagged at least as pretty good. Make those rules community-reviewed and you normalize people's needs. I'm pretty sure much of D was decided this way. Also, if you are really thorough in deciding how to break the pieces of the system, then maybe people won't be too bothered if it's a bit off their tastes. -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Is this a viable effort? The DRY principle, community-wide
I may sound daring or even foolish proposing this, but here goes nothing.. one of the things that bothers me about software development is that people always tell you not to reinvent the wheel, but the libraries available are generally not fine-grained enough, so you end up either using overkill solutions to ridiculously small problems or actually reinventing the wheel. For example, what do you do if you want to create a window just for use with OpenGL in a cross-platform way? You have to write different versions of the window creation procedure for the different systems you're targeting. Or you could use SDL, but if you really just want the window that's a waste. Right? At times like this I wish people would really break their code in smaller parts in a way you could really just pick what you want from it. So I thought, since D has such a compact community and the codebase is still small, maybe you would like to attack the problem (dunno if many will agree with me this is a problem, but then I'd like to know what they do in the case I described) together. I'd like to propose a community-written, community-reviewed hierarchy of modules anybody could (and should :)) contribute to. Necessities would be factored and layered before entering the actual hierarchy, though. For example, right now I really wanted a cross-platform way of using OpenGL. AFAIK, OpenGL usage is normalized across many systems and only its initialization is platform-depedent (to begin with, there's WGL, GLX and AGL; plus, you have very different ways of creating windows in those systems, so you need to do a lot of work to really use OpenGL in a cross-platform manner). I would then engage into writing what's needed and, when done, I would send it for the community to review. The modules would be fragmented, trying not to compromise its usability in any possible use-case. The core notion here is that D libraries could be the community's, not the author's. I wonder if merging people's efforts can be a good idea. I mean, you would avoid reinventing the wheel, you would avoid having many libraries doing the same thing with different interfaces, essentially making two user-libraries, each using one of the first ones, incompatible when in a perfect world they really shouldn't be, etc. So, what do you think? - Is it viable? - Would it be useful? - Improvements? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: memoize
On Tue, Jan 4, 2011 at 2:50 AM, Nick Sabalausky a...@a.a wrote: Andrei Alexandrescu seewebsiteforem...@erdani.org wrote in message news:ifu70u$2dv...@digitalmars.com... I just added a higher-order function memoize to std.functional which I think is pretty cool. See the docs here: http://d-programming-language.org/cutting-edge/phobos/std_functional.html#memoize I'm also thinking of adding that cutting-edge directory as a place for storing documentation for commits that are in flux but not officially released yet. Andrei Neat! This is a great example of why D kicks so much ass :) Uh, yes. It looks like the kind of thing I would do, show to others and hear they say Meh.. Whatever. I'm really exponentially developing a liking to the D community, even though I didn't event get to code anything serious yet. This simply rocks. Keep it up, Andrei! -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: A (un)stable idea?
On Tue, Jan 4, 2011 at 3:07 AM, Heywood Floyd soul...@gmail.com wrote: Hi D! I'm quite new to D (been here for maybe half a year?) and I'm not sure if what I'm about to say is called for, so please forgive me if I'm crossing some line here. I just had a thought and I wanted to share it: I've noticed, during my time here, that D seems to suffer from quite a lot of frustration. This frustration in turn seems to stem from periodical annoying bugs and regressions etc. There are stories of dedicated developers abandoning the ship and things like that. I'm not really in a position to say if this is normal or not, but I think at least it's fair to say a lot of poeple are frustrated with D(?). At the same time, what's interesting is that these kinds of bugs can hardly be unique to D -- in fact, it would be really weird if these kinds of issues was not present in D! (I think so, at least.) Software is complex, and we all know bugs are part of the normal course of things. I'd go so far to say bugs are a natural part of software. So why all the frustration? This lead me to a thought: maybe, just maybe, one thing that causes so much frustration, is the fact that D doesn't really seem to have any testing / stable branches. Seems to me, and please correct me if I'm wrong, changes made to the trunk are released about once every month? And that's it. That's the latest version of D. This is very agressive. Isn't it? Seems to me, many people hold off the latest version of D, because it's so agressive. I think most non-trivial software projects keep one branch that is the sand box-branch where new features are tried out, and one branch where special care is taken to keep it stable. Now, this setup doesn't mean that the software will be bug free. The _key_ here is, that once you label a piece of software as testing or experimental, bugs are ok! In fact, bugs are to be expected! No one can complain! (And if they do, you say hey, chillax dude, it's experimental!) Also, most developers will be in different phases in their projects -- some are building on some project that is years old and the last thing they want is some new experimental feauture. Others are just playing around and don't mind getting all the latest bells and whistles. Testing/stable solves all that, while still allowing the software to evolve. Then of course, you have to actually keep the stable branch stable. I realize that simply dividing D(2) into two branches wouldn't achieve that. So I don't know. I guess this is more an idea for future version of D? That's it. I'm not quite going to finish my reasoning, because, yeah I don't know. Maybe this has been up before? Sorry in that case. I just wanted to give this idea some air: How about maybe having a testing/stable branch for D at some point in the future? I for one would like that, anyhow. (Fun thought experiment: Imagine Debian Linux abandoning their testing branch and just making all changes to trunk. Imagine _that_ mailing list. You can feel the frustration, can't you? :) Kind Regards /HF PS. I've too experienced some frustrating bugs with D, but it's still the only compiled language I can stand! *bow* Shouldn't TDPL have set the safe subset of the language to use? Maybe it only happens much when you cross that line? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: memoize
On Tue, Jan 4, 2011 at 4:05 AM, Andrew Wiley debio...@gmail.com wrote: On Mon, Jan 3, 2011 at 10:15 PM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I just added a higher-order function memoize to std.functional which I think is pretty cool. See the docs here: http://d-programming-language.org/cutting-edge/phobos/std_functional.html#memoize I'm also thinking of adding that cutting-edge directory as a place for storing documentation for commits that are in flux but not officially released yet. Pretty sweet, but if I'm understanding this correctly, the memoized version of a pure function isn't pure, is it? Is there any way to get that to happen? memoize uses a static variable. Are static variables considered global as far as pure functions are concerned? If not, then I see no reason for it not to be pure, or am I missing something? Additionally, I don't understand this: Technically the memoized function should be pure because memoize assumes it will always return the same result for a given tuple of arguments. However, memoize does not enforce that because sometimes it is useful to memoize an impure function, too. Wouldn't memoizing an impure function be a.. bug? It would return the same cached value when in fact it should have returned something else based on external factors. When can that be desirable? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: memoize
On Tue, Jan 4, 2011 at 3:27 AM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: On 1/3/11 11:01 PM, Guilherme Vieira wrote: On Tue, Jan 4, 2011 at 2:50 AM, Nick Sabalausky a...@a.a wrote: Andrei Alexandrescu seewebsiteforem...@erdani.org mailto:seewebsiteforem...@erdani.org wrote in message news:ifu70u$2dv...@digitalmars.com... I just added a higher-order function memoize to std.functional which I think is pretty cool. See the docs here: http://d-programming-language.org/cutting-edge/phobos/std_functional.html#memoize I'm also thinking of adding that cutting-edge directory as a place for storing documentation for commits that are in flux but not officially released yet. Andrei Neat! This is a great example of why D kicks so much ass :) Uh, yes. It looks like the kind of thing I would do, show to others and hear they say Meh.. Whatever. I'm really exponentially developing a liking to the D community, even though I didn't event get to code anything serious yet. This simply rocks. Keep it up, Andrei! -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira Glad you folks like it. There's a little story behind this. I first read Dominus' book chapter years ago, around the time I'd decided to write TDPL. Back then I was thinking - it would just be so cool to be able to define generic memoization in D. I tried my hand at an implementation. But D had no tuples, no aliasing for functions, no good variadics, and even if you could find a way to pack parameters, associative arrays had plenty of related issues. I'd given up on that and forgot most about it, until today. It was nice to reckon that getting it done took about a dozen lines and about as many minutes. We really have come a very long way. Nevertheless, I found two issues: one, ParameterTypeTuple doesn't work for overloaded functions, and associative arrays don't work for ubyte[4] keys... still a ways to go. Andrei Is there really need for ParameterTypeTuple? I figured this works: template memoize(alias fun, uint maxSize = uint.max) { auto memoize(Args...)(Args args) { static typeof(fn(args))[Tuple!(typeof(args))] memo; auto t = tuple(args); auto p = t in memo; if (p) return *p; static if (maxSize != uint.max) { if (memo.length = maxSize) memo = null; } auto r = fun(args); //writeln(Inserting result , typeof(r).stringof, (, r, ) for parameters , t); memo[t] = r; return r; } } -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: memoize
On Tue, Jan 4, 2011 at 4:48 AM, Jonathan M Davis jmdavisp...@gmx.comwrote: On Monday 03 January 2011 22:17:52 Guilherme Vieira wrote: On Tue, Jan 4, 2011 at 4:05 AM, Andrew Wiley debio...@gmail.com wrote: On Mon, Jan 3, 2011 at 10:15 PM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: I just added a higher-order function memoize to std.functional which I think is pretty cool. See the docs here: http://d-programming-language.org/cutting-edge/phobos/std_functional.htm l#memoize I'm also thinking of adding that cutting-edge directory as a place for storing documentation for commits that are in flux but not officially released yet. Pretty sweet, but if I'm understanding this correctly, the memoized version of a pure function isn't pure, is it? Is there any way to get that to happen? memoize uses a static variable. Are static variables considered global as far as pure functions are concerned? If not, then I see no reason for it not to be pure, or am I missing something? pure functions cannot access mutable globals or static variables. If they could, they could end up returning a different result with the same parameters because the global or static variable changed. Additionally, I don't understand this: Technically the memoized function should be pure because memoize assumes it will always return the same result for a given tuple of arguments. However, memoize does not enforce that because sometimes it is useful to memoize an impure function, too. Wouldn't memoizing an impure function be a.. bug? It would return the same cached value when in fact it should have returned something else based on external factors. When can that be desirable? It's quite easy to have a function which you cannot actually make pure but which you know to be logically pure. For instance, if a function called a C function, it can't be pure unless you play some games with function pointers and casting and the like. So, really, any function which calls a C function can't be pure. However, it's pretty easy to have a C function which is logically pure. So, your D function is then logically pure, but it's not actually pure, so pure functions can't call it. But it would work just fine with memoize. Sure, it's definitely less safe to use impure functions with memoize, and it could cause bugs, but that doesn't mean that it shouldn't necessarily be disallowed. It just means that if the programmer wants to use memoize, they're going to have to be aware that it could cause bugs if the function in question should actually be returning a different value on future callls. - Jonathan M Davis Ah, I was under the impression that @trusted was used to force purity. Shame.. Sorry I mixed things up. In any case, aren't those rules a bit too rigid? No matter how you look at memoize, it should generate pure functions (since it exhibits pure nature, are logically pure or whatever you call it). Would it be tough on the compiler for it to actually find if a function is pure or not by a more detailed analysis of its behavior? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: memoize
On Tue, Jan 4, 2011 at 5:28 AM, Jonathan M Davis jmdavisp...@gmx.comwrote: On Monday 03 January 2011 22:59:37 Guilherme Vieira wrote: Ah, I was under the impression that @trusted was used to force purity. Shame.. Sorry I mixed things up. In any case, aren't those rules a bit too rigid? No matter how you look at memoize, it should generate pure functions (since it exhibits pure nature, are logically pure or whatever you call it). Would it be tough on the compiler for it to actually find if a function is pure or not by a more detailed analysis of its behavior? @safe, @trusted, and @system have nothing to do with purity. If a function is marked as pure, then it's pure. If it's not, then it's not. End of story. Now, the concept of weakly pure functions was recently added, but all pure functions are still marked with pure. Strongly pure functions are pure functions where all of the parameters are immutable or implicitly convertible to immutable (so, immutable variables and value types). Weakly pure functions are pure functions whose parameters are not all immutable or implicitly convertible to immutable. Unlike strongly pure functions, they can alter their arguments. However, just like strongly pure functions, they cannot access globals or statics. Strongly pure functions can be optimized such that only one call to them is made in an expression because their return value will always be the same, and they cannot alter their parameters. Weakly pure functions cannot be optimized in that manner, but because they don't alter the global state, they can be safely called from strongly pure functions without violating the strongly pure function's purity. Pure is not logically pure for essentially the same reasons that const is not logically const. Making it logical instead of guaranteed eliminates the guarantees, and the compiler can no longer rely on those guarantees, making them _far_ less valuable. It is true that a memoized function must be logically pure, or you're going to get errors. However, if you were to force such functions to be pure, it would be highly limiting. And since memoize _can't_ be pure, it would make recursion with memoize impossible. True, allowing for memoized functions to be impure makes it so that the programmer must be more careful, but it's still quite useful - in fact more useful - that way. And since you _can't_ have memoize be pure anyway, it's not like you're losing any guarantees from the compiler like if you tried to make pure logically pure or const logically const. - Jonathan M Davis Don't take me too seriously since I'm learning those things on-the-fly here (I'm greedy). The const FAQ ( http://www.digitalmars.com/d/2.0/const-faq.html#logical-const) says D doesn't support logical const because it would break transitivity, and they deemed transitivity to be more important (Walter even thinks it's bad, doesn't he?), so I understand why const in D is not logical const. But in the case of memoize, aren't there things that can be done to the language spec to allow it to be pure? Maybe by adding some language construct, I dunno. Or by analysis of behavior. Obviously, that wouldn't work for external C functions, but at least memoize would be okay. Also, I'm to guess it would be extremely hard to write a compiler that does this, but I'd just like to confirm. @Walter: would it be hard/impossible for the compiler to look at memoize and tell it exhibits pure behavior and is, thus, pure? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: D for game development
On Fri, Dec 31, 2010 at 4:08 PM, Andrei Alexandrescu seewebsiteforem...@erdani.org wrote: A discussion to which I think some of us could add value: http://stackoverflow.com/questions/4516283/the-d-programming-language-for-game-development Andrei Lambert's answer says the compilers are definitely not bug-free and all, but is it really that bad? In a medium-sized project, do the compiler bugs really get all too frequent or something, and if so, is it simple to find workarounds? Because I guess, quite frankly... if Derelict works, I have nearly no reason to keep doing C++. In fact, the ease of meta and generative programming in D makes me wonder if it's not much easier make the game engine in it. -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: D for game development
On Sat, Jan 1, 2011 at 3:22 PM, Jimmy Cao jcao...@gmail.com wrote: Right now I'm trying out the approach of making existing C++ 3D engines available for D. SWIG is very instrumental in the process. I hope that after the 64-bit issues are worked out, some special attention can be applied to the D language issue(s) that make it harder for SWIG to effectively generate D code. It's certainly a worthy effort. Having high-level libraries in D are a good way of getting people to learn it faster by trying things they find fun (such as making games). But I think I'll take another route if I have the time to write games in D. I don't think I would like to make a game using one of those anymore (I had a sorta bad experience with Ogre in which it kept getting on my way, or maybe I was just silly and disliked its style; in any case, I'd rather do things from scratch now, since it's also good for learning). In any case, two efforts are better than one. Much appreciated! I hope we can help ourselves out. :) -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Happy New Year!!!
On Fri, Dec 31, 2010 at 2:43 PM, Stanislav Blinov stanislav.bli...@gmail.com wrote: Somebody's already celebrating, somebody's only anticipating, but regardless HAPPY NEW YEAR, EVERYONE!!! HAPPY NEW YEAR, D!!! Happy new year from Brazil :) -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: discrimination of constructors with same number of parameters
On Thu, Dec 30, 2010 at 9:24 AM, bearophile bearophileh...@lycos.comwrote: Jonathan M Davis: typedef is definitely on the way out, so that's not a solution, typedef is deprecated (because its semantics is not flexible enough and because it doesn't play well with object oriented language features), but I have a real need for something like it. Andrei has discussed about a Phobos-based typedef replacement (based on structs + alias this), but nothing concrete has come out yet. I hope to see something to solve problems like spir ones. and it would be a pretty fragile one IMHO anyway. Please, explain better. Bye, bearophile As far as I know, typedef was a form of discriminated alias. I don't know the reasons for its deprecation. It just occurred to me that D's typedefs + templates could be quite handy in this case. Consider: struct semantic_wrapper(T) { this(T value) { this.value = value; } T value; } typedef semantic_wrapper!(int) Position; typedef semantic_wrapper!(size_t) Count; typedef semantic_wrapper!(string) Filename; typedef semantic_wrapper!(string) DirPath; void func(Position pos) { ... } void func(Count c) { ... } void func(Filename fname) { ... } void func(DirPath dir) { ... } void main() { func(Position(1)); // calls first overload func(Count(5)); // calls second func(Filename(file.txt)); // third func(DirPath(/dev/null)); // fourth func(1); // fails func(blah); // fails } Requires a little more typing, but sometimes it can be better than creating a new function name (which can get extra-big, non-telling or both) or than creating factory methods (which I personally dislike, although it's just a matter of taste most of the time; sometimes you may want to instantiate from inside a template and classes needing factories would not work, for example, but one could argue on the validity of this anytime). Just giving my 2 cents. Dunno if I missed some detail. -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: discrimination of constructors with same number of parameters
On Thu, Dec 30, 2010 at 12:18 PM, spir denis.s...@gmail.com wrote: On Thu, 30 Dec 2010 08:15:51 -0500 bearophile bearophileh...@lycos.com wrote: But some language types (or machine types) can have very diverse _human_ semantics, and thus be used for various purposes which should, but cannot, be considered different: You may wrap your data in a struct. Yes, thank you for this hint. A kind of proxy struct? It can indeed be used everywhere performance is not critical. But a side issue is that it requires the 'alias this' hack, I guess, or forwarding every operation to the actual, but wrapped, element. What do you think Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com Why is performance harmed by the use of a struct? Wouldn't it be zero-overhead like C++'s std::auto_ptr? Also, the alias this and the forward might be a real good solution. And a mixin like Luger's might be jackpot, really. I just dislike the use in: func2(Position(1)); // implicit conversion to int with alias this I guess that can be actually a bug, not a feature :) Maybe one day the function signature changes slightly and the problem is further disguised because you're obviously passing the right Position here... when it's actually an int count thing. The alias this thing is a good shorthand when assigning, though: int a = pos; // implicit conversion from Position to int instead of int b = pos.base; -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: discrimination of constructors with same number of parameters
On Thu, Dec 30, 2010 at 3:19 PM, Steven Schveighoffer schvei...@yahoo.comwrote: On Thu, 30 Dec 2010 12:08:56 -0500, spir denis.s...@gmail.com wrote: On Thu, 30 Dec 2010 17:10:00 +0100 Jérôme M. Berger jeber...@free.fr wrote: Steven Schveighoffer wrote: What I would suggest is static factory methods. The issue with any kind of typedef (be it with the soon-to-be-deprecated typedef keyword or with a proxy struct), is that what does this mean? auto obj = new Foo([1, 2, 3], blah); Is blah a filename or a message? -- Error, Foo (int[], string) does not exist. Yes, you are right. Typedef-like solutions need core support by the language with a kind of hint to the compiler... playing the role of type in Jérôme's sample below. I expected a definition like this: typedef string filename; this(int[] x, string message); this(int[] x, filename file); Which would be more ambiguous in usage. So your version (with two typedefs) is better. Whereas, if you use factory methods: auto obj = Foo.createWithFilename([1,2,3], blah); // blah is a filename auto obj = Foo.createWithMessage([1,2,3], blah); // blah is a message Factory methods are definitely convenient. The single objection is rather conceptual: it defeats the purpose of a major language feature, namely constructor; which happens to have a clear meaning from the modelling point of view. This doesn't mean much to me. I don't see the benefit of using 'new' vs. using a static factory method. What is the clear meaning that constructors have that factory methods do not? The code becomes crystal clear. Reduce verbosity as you see fit ;) auto obj = new Foo ([1, 2, 3], Filename (blah)); auto obj = new Foo ([1, 2, 3], Message (blah)); Conceptually, I would prefere this -- at the use place. But if requires obfuscating the code at the definition point (with eg wrapper structs), is it worth it? If we could write eg: typedef string Message; auto obj = new Foo ([1, 2, 3], Message (blah)); then I would be happy, I guess ;-) Wait, this isn't any different than using a wrapper struct... struct Message { string value; } struct Filename { string value; } class Foo { string message; string filename; int[] arr; this(int[] arr, Message m) {this.arr = arr; this.message = m.value;} this(int[] arr, Filename f) {this.arr = arr; this.filename = f.value;} } How is that obfuscation? I still prefer the factory method solution, as it doesn't add unecessary types. -Steve There's an idiom I'm quite fond of. There are some classes you shouldn't be instantiating yourself. Take for example a SoundSource class, which represents a source of sound in a 2D or 3D environment. It's obvious that it requires the SoundSystem to be initialized when it's created, unless it used lazy initialization of the sound system (which I dislike, since everytime you create an object it'll have to check whether the system is initialized or not). As such, it makes sense that the architecture guide client developers to only instantiate after initializing the system. If you normally simply *new*SoundSources yourself, it's not hard to forget the sound system initialization. So I prefer to make the SoundSystem class a factory of SoundSources (Ogre3D does such things a lot), and it's particularly damn great to create template methods such as these: class SoundSystem { Unique!(TSoundSource) createSource(TSoundSource, CtorArgs...)(CtorArgs ctorArgs) { // reserves first argument for mandatory parameters, but leaves the rest client-defined return new TSoundSource(this, ctorArgs); } } // later ... sndSystem.createSource!(MySoundSource)(my, custom, parameters); In this case, constructing the SoundSource required a SoundSystem as a parameter, so yeah, you would need the thing to be able to instantiate alright. But it surely gives margin to misuses: if you, as the library developer, noticed that *any* SoundSource implementation should get the SoundSystem upon construction from the caller (and not try to tell which system to use by e.g. picking it from a singleton of the likes), then this idiom is useful. I find this kind of usage extremely expressive (in fact, I'd like to take the moment the ask what the gurus think about it; I really have never seen people doing this). It shows precisely how the library is meant to be used. The least wrong things you can do, the better, so getting rid of the possibility of instantiating things at the wrong times is certainly good. And static factories succeed in making such things harder. Yes, you could wrap classes in structs that would construct them using one factory or another, but making useful idioms more and more cumbersome to use is almost never a good idea: struct MyObjectWithFileName // this { // is this(string fname) { obj = MyObject.createWithFilename(fname); } // so MyObject obj; // much } // typing!
Re: Clay language
On Mon, Dec 27, 2010 at 4:35 PM, bearophile bearophileh...@lycos.comwrote: Through Reddit I have found a link to some information about the Clay language, it wants to be (or it will be) a C++-class language, but it's not tied to C syntax. It shares several semantic similarities with D too. It looks like a cute language: https://github.com/jckarter/clay/wiki/ Some small parts from the docs: -- In Clay this: https://github.com/jckarter/clay/wiki/Syntax-desugaring static for (a in ...b) c; is equivalent to: { ref a = first element of b; c; } { ref a = second element of b; c; } /* ... */ I have an enhancement request about this for D: http://d.puremagic.com/issues/show_bug.cgi?id=4085 The part about Safer pointer type system is very similar to what I did ask for D, and it looks similar to what Ada language does (for Clay this is just a proposal, not implemented yet, but Ada is a rock-solid language): https://github.com/jckarter/clay/wiki/Safer-pointer-type-system This is something that I want for D too, it's important: Jonathan Shapiro (of BitC) makes an excellent argument that, in a systems language, it is often undesirable to depend on the whims of an ill-specified optimizer to convert abstract code into efficient machine code. The BitC specification thus includes the idea of guaranteed optimizations, to allow code to be written in a high-level style with predictably low or nonexistent runtime cost (link). [...] Because Clay seeks to support systems programming with high-level abstraction, certain patterns should be guaranteed to be optimized in a certain way, instead of being left to the whims of LLVM or a C compiler. Additional optimizations should not be prevented, however. [...] It should be possible to specify that one or more of these optimizations is required, and have the compiler raise an error when they cannot be applied for some reason. https://github.com/jckarter/clay/wiki/Guaranteed-optimizations Bye, bearophile +1 for static for and guaranteed optimizations. Can we put it in the wishlist? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Re: Creating an array of unique elements
On Mon, Dec 27, 2010 at 12:14 PM, Guilherme Vieira n2.nitro...@gmail.comwrote: Ah, yeah. I think you're right. Set is exactly what I need, and the fact that it works with hashes is even better. A pity D still doesn't have it, since it looks very useful, but thanks for your response. I'll take a look at your implementation later. Is there any prevision for sets in core D or Phobos? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira On Mon, Dec 27, 2010 at 11:39 AM, spir denis.s...@gmail.com wrote: On Mon, 27 Dec 2010 05:22:14 -0200 Guilherme Vieira n2.nitro...@gmail.com wrote: Right now I'm wondering how's the best way to create a dynamic array object which will only accept unique elements (i.e., elements != from the existing elements in the array). (Take my words with precaution because I don not know D very well myself.) Hello Guilherme. If I understand your purpose correctly, what you're trying to define is a set, not an array, in the common sense of the terms in programming. To ensure uniqueness, you'd need to check whether the element exits already, which can only be very slow using an array (O(n)): you need to traverse the array element per element. Sets instead are build using data structures that allow this check to be far faster, by looking up a given element in a more clever way. There is no builtin Set type in D yet. The simplest way (and maybe the best) would be use associative arrays where keys would be actual elements and values just fake. (e in set) would tell you what you need. Depending on your requirements, trying to put an existing element would just put it again with no change, or should throw an error. In the latter case, you need to check it yourself or build a wrapper type (struct or class) around builtin associative arrays. For instance: Existence[Element] set; Element[] elements = ['a','c','e']; Element[] values = ['a','b','c','d','e']; foreach (element ; elements) set[element] = EXISTS; // Note: 'in' actually return a pointer to element. foreach (value ; values) writeln(cast(bool)(value in set)); Note: I have a Set type in stock at https://bitbucket.org/denispir/denispir-d/src/b543fb352803/collections.d, but wonder whether it's really necessary given the above. But you can have a look to see how it's done (this would give you some hints about language methods called 'opSomething', see TDPL's index). Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com Eek..! sorry for top-posting. -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira
Creating an array of unique elements
Hi, guys. — said the shy newcomer. I've started reading The D Programming Language just yesterday and I'm making my first attempts to dig into D now. I must say I'm loving the language beyond recognition. I never thought there was a language out there that had everything I ever wanted in C++ (I even considered developing my own language before knowing D!). Right now I'm wondering how's the best way to create a dynamic array object which will only accept unique elements (i.e., elements != from the existing elements in the array). I wanted a class that kept all the functionality of an array (e.g. being the right range types so that they can be passed to std.format.formatValue and trigger the right specialization) for maximum integration with the standard library. I thought about writing a class template privately containing an array and redirecting everything but the assignment/insertion operations to it. All ways of placing an object that was already there should throw an exception, but everything else should work the same. Doing it this way is a lot of work for a simple thing, so some sort of internal alert in me tell me I might just be doing-it-wrong. I want to know what your ideas are. I want some way to achieve this sort of thing: import myproject.helpers.UniqueArray; void main() { auto a0 = [1, 2, 3]; // I'm not yet sure how to go about the constructor, since: auto a1 = UniqueArray!(int)(a0[1 .. $]); // error: should not be able to internally hold reference to // a raw array since this could be used to break the unique // elements contract promise of UniqueArray // copy of elements can be considered, but I'd rather // have clients copy the array themselves so that they // know it is happening auto a2 = UniqueArray!(int)(a0[1 .. $].dup); // should be fine if D had some sort of non-const // rvalue reference support, but I think it does not; // am I wrong? auto a3 = UniqueArray!(int)(a0[1 .. $].idup); // semantically pleasing at first sight, but // suboptimal: the constructor would have to copy // the passed array again to get rid of immutability auto a4 = bestOptionOutOf(a1, a2, a3); // (: a4[1 .. $] = [3, 4, 5]; // ok: would first construct a UniqueArray out of the rvalue (thus ensuring // uniqueness of elements) and then would work like a usual slice // assignment a4 ~= 5; // throws exception: 5 is already in the array! a4 ~= 6; // ok: 6 is not there writeln(a4); // ok, output: [2, 3, 4, 5, 6] // could just implement UniqueArray.toString() for this to work, but making UniqueArray // properly model the ranges an array models solves this problem and others at the same // time auto a5 = a4.dup; // all properties of an array, such as dup here, should hold and overall // the object should behave as one would expect from an array int[] a6 = a5; // error: obviously shouldn't work since a6 could then be used to break the // UniqueArray contract } What do you think? -- Atenciosamente / Sincerely, Guilherme (n2liquid) Vieira