phobos / tango / ares

Kevin Bealer kevinbealer at gmail.com
Sat Feb 10 17:55:50 PST 2007


Max Samukha wrote:
> On Fri, 09 Feb 2007 01:40:00 -0500, Kevin Bealer
> <kevinbealer at gmail.com> wrote:
> 
>> Okay -- I'm really sorry if any of this seems to have a negative tone. 
>> I hesitate to write this since I have a lot of respect for the Tango 
>> design in general, but there are a couple of friction points I've noticed.
>>
>> 1. writefln / format replacements
>>
>> Concerning standard output and string formatting, in phobos I can do 
>> these operations:
>>
>>   writefln("%s %s %s", a, b, c);
>>   format("%s %s %s", a, b, c);
>>
>> How do I do these in Tango?  The change to "{0} {1}" stuff is fine with 
>> me, in fact I like it, but this syntax:
>>
>>   Stdout.formatln("{0} {1} {2}", a, b, c);
>>   Format!(char).convert("{0} {1} {2}", a, b, c);
>>
>> Is awkward.  And these statements are used *all the time*.  In a recent 
>> toy project I wrote, I used Stdout 15 times, compared to using "foreach" 
>> only 8 times.  I also use the "format to string" idiom a lot (oddly 
>> enough, not in that project), and it's even more awkward.
>>
>> That's why I think phobos really did the "Right Thing" by keeping those 
>> down to one token.  Second, the fact that the second one does exactly 
>> what the first does but you need to build a template, etc, is annoying. 
>>  I kept asking myself if I was doing the right thing because it seemed 
>> like I was using too much syntax for this kind of operation (I'm still 
>> not sure it's the best way to go -- is it?)
>>
>> I know about Cout as a replacement for the first one, but as far as I 
>> can tell it doesn't take parameters, and usually I need some.
>>
>> When people ask "why D", I tell them that simpler syntax, better 
>> defaults and better garbage collection, each gain us a 50 % reduction in 
>> code, and when all three apply to a problem, D can each C++'s lunch. 
>> Let's not throw away the simpler syntax.
>>
>> (I'm not talking about architecture changes, just wrappers with 
>> standardized short names that can become familiar to all D users.)
>>
>>
>> 2. toString and toUtf8 (collisions)
>>
>> The change of the terminology is actually okay with me.
>>
>> But phobos has a way of using toString as both a method and a top-level 
>> function name, all over the place.  This gets really clumsy because you 
>> can never use the top level function names when writing a class unless 
>> you fully qualify them.
>>
>> For example, std.cpuid.toString(), always has to be fully qualified when 
>> called from a class, and seems nondescriptive anyway.  All the 
>> std.conv.toString() functions are nice but it's easy to accidentally 
>> call the in-class toString() by accident.
>>
>> For the utf8 <--> utf16 and similar, it's frustrating to have to do this:
>>
>> dchar[] x32 = ...;
>> char[] x8 = tango.text.convert.Utf.toUtf8(x32);
>>
>> But you have to fully qualify if you are writing code in any class or 
>> struct.  If these were given another name, like makeUtf8, then these 
>> collisions would not happen.
>>
>> Actually, if it wasn't already out there, I would want to go through all 
>> of phobos and remove all the common collisions.  They are much less 
>> trouble in an "import" system than in an "include" system, but every 
>> time there is a collision it requires an additional "edit-compile" 
>> cycle, and/or a fully qualified name.
>>
>> And if you forget to import all the right modules, its can impact the 
>> correctness angle, because you pick up someone else's "toString" from 
>> who knows where.
>>
>> I'm just saying, ideally tango should not be duplicating this with 
>> toUtf8 etc.
>>
>> Kevin
> 
> If you really want the 'writefln' and 'format' with Tango, you could
> do the following:
> 
> import tango.io.Stdout;
> import tango.text.convert.Format;
> 
> 
> Format!(char) format;
> typeof(&Stdout.formatln) writefln;
> 
> static this()
> {
> 	writefln = &Stdout.formatln;
> 	format = new Format!(char);
> }
> 
> void main()
> {
> 	auto str = format("Test {0}: {1}", 1, "Passed");
> 	writefln(str);
> 	writefln("Test {0}: {1}", 2, "Passed");
> }

Right - this is good.  But almost everyone will eventually do this, so 
What I'm also suggesting though is that this be done in the module, so 
that everyone who imports the module doesn't need to cut and paste or 
invent something like the above in their code.

If it's done in the module it helps readability of all user code because 
you don't need to see what particular identifier is used by each coder. 
  Sort of like in C++ where you see this all the time:

Int1, Uint1, Int2, Uint2, Int4, Uint4, Int8, Uint8 // label=#bytes

   in another project they will use

int8_t, uint8_t, ... int64_t, uint64_t // label=#bits

If you use a library from ncbi, another from GTK, another from Qt, etc, 
you eventually have a dozen types with a three or four synonyms for each 
one.

Kevin


More information about the Digitalmars-d-learn mailing list