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
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: 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: 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