Struct constructors callable twice?

2011-01-12 Thread Guilherme Vieira
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?

2011-01-12 Thread Guilherme Vieira
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

2011-01-08 Thread Guilherme Vieira
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

2010-12-30 Thread Guilherme Vieira
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

2010-12-30 Thread Guilherme Vieira
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

2010-12-30 Thread Guilherme Vieira
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

2010-12-27 Thread Guilherme Vieira
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

2010-12-26 Thread Guilherme Vieira
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