April 30, 2012
On 30/04/12 12:27, Manu wrote:
> On 30 April 2012 10:32, Don Clugston <dac@nospam.com
> <mailto:dac@nospam.com>> wrote:
>
>     On 29/04/12 20:08, Manu wrote:
>
>         On 29 April 2012 18:50, Don <nospam@nospam.com
>         <mailto:nospam@nospam.com>
>         <mailto:nospam@nospam.com <mailto:nospam@nospam.com>>> wrote:
>
>
>             On 28.04.2012 20:47, Walter Bright wrote:
>
>                 Andrei and I had a fun discussion last night about this
>                 question. The
>                 idea was which features in D are redundant and/or do not add
>                 significant
>                 value?
>
>                 A couple already agreed upon ones are typedef and the
>         cfloat,
>                 cdouble
>                 and creal types.
>
>                 What's your list?
>
>
>             * The >>> operator, which does nothing except introduce bugs (It
>             does NOT perform an unsigned shift).
>
>
>         What does it do? I use this all over the place, I assumed it
>         worked...
>         maybe I have bugs?
>
>
>     It works only for two types: int and long.
>     For everything else, it is identical to >>
>     So for short and byte, and in generic code, it's ALWAYS a bug.
>
>
> O_O
> Is that intentional? Or is it... a bug?
> I smiled when I saw >>> in the language, I appreciate its presence. It's
> not necessary, but it cuts down on some ugly explicit casting (which
> theoretically makes generic code simpler).

It's not a bug, it's a design flaw. The buggy behaviour is explicitly tested in the test suite.
The problem is that the C promotion rules also apply, just as for >> and <<. But they are fundamentally incompatible with unsigned shift.
So short and byte get promoted to int *by sign extension*,
then the int gets an unsigned shift.
Which means that the short or byte gets a signed shift instead of an unsigned one.

I used to use >>> in my code, because as you say, it is a nice idea, but after having a few bugs with short, and working out what the semantics actually were, I suddenly realized it was a landmine, and I removed every instance of it from my code.

(cast(ulong)x) >> 3 is safer than x >>> 3, unfortunately.
April 30, 2012
On Monday, 30 April 2012 at 12:35:24 UTC, deadalnix wrote:
> Phobos is a really good example. Modules tend to become more and more fat. And to split them up, package is mandatory.

Except that it doesn't work if the module you want to refactor into a sub-package already used »package«…

David
April 30, 2012
On 30-04-2012 12:18, foobar wrote:
> Meta comment: C++ is the spawn of the devil so I don't accept anything
> related to c++ as a valid argument.
>
> On Sunday, 29 April 2012 at 20:09:34 UTC, Alex Rønne Petersen wrote:
> [...]
>>>
>>> I have used D and didn't claim that foreach isn't useful.
>>> What I said that is that it belongs in the library, NOT the language.
>>
>> Yeah, we tried that in C++. It sucked.
>
> See meta comment above.
>
>>
>> The reason it works for many functional languages is that they have
>> even more terse syntax than D. It would suck to make foreach a
>> function in D.
>>
>
> D wants to support functional programming. That means we should provide
> whatever is necessary to write functional style code including foreach
> methods. IF D can't properly implement a FP foreach method (And IMO it
> *can*) than we have failed.

Of course it can, but not with type inference, unless you templatize it. That is:

void forEach(alias fun, R)(R range)
{
    // ...
}

enjoys type inference: forEach!(item => foo(item))(myRange);

But this doesn't:

void forEach(R)(R range, scope void delegate(ElementType!R) dg)
{
    // ...
}

This won't work: forEach(myRange, item => foo(item));

You have to do: forEach(myRange, (ElementType!(typeof(myRange)) => foo(item));

which, frankly, sucks.

>
>>>>
>>>>> * version - this does not belong in a programming language. Git
>>>>> is a much better solution.
>>>>>
>>>>
>>>> So you'd maintain a git branch for every OS if there is some small
>>>> part that is OS-dependent? I don't think that is a better approach at
>>>> all.
>>>
>>> It is far better than having a pile of #ifdef styled spaghetti code.
>>> I'd expect to have all the OS specific code encapsulated separately
>>> anyway,
>>> not spread around the code base. Which is the current recommended way of
>>> using
>>> versions anyway. The inevitable conclusion would be to either use a
>>> version management system like git or have separate implementation
>>> modules for platform specific code and use the build tool to implement
>>> the logic of select the modules to include in the build.
>>
>> Yeah, we tried that in C and C++. It sucked. See: Autotools.
>>
>
> see meta comment above.
> The fact that you used a horribly designed language with a horrible mess
> of a "build tool" made out of shell scripts IIRC is not an indication
> that the language should include build-tool functionality.
>


-- 
- Alex
April 30, 2012
On 30-04-2012 09:08, Jacob Carlborg wrote:
> On 2012-04-29 22:26, Alex Rønne Petersen wrote:
>
>> IMHO r"" is better than `` for the simple reason that typing `` is
>> extremely annoying on non-US keyboards.
>
> `` is better because you don't have to escape ".
>

That only applies when you actually have " in the string. I think both have their uses.

-- 
- Alex
April 30, 2012
On 30-04-2012 11:46, SomeDude wrote:
> On Monday, 30 April 2012 at 03:16:57 UTC, Alex Rønne Petersen wrote:
>>
>> The problem with D's unit test support is that it doesn't integrate
>> well into real world build processes. I usually have debug and release
>> configurations, and that's it. No test configuration; not only does
>> that over-complicate things, but it also isn't really useful. I want
>> my unit testing to be exhaustive; i.e. I want to test my code in debug
>> and release builds, because those are the builds people are going to
>> be using. Not a test build.
>>
>> So, this means that writing unit tests inline is a no-go because that
>> would require either always building with unit tests in all
>> configurations (madness) or having a test configuration (see above).
>>
>> Given the above, I've resorted to having a "tester" executable which
>> links in all libraries in my project and tests every module. This
>> means that I have to write my unit tests inside this helper
>> executable, making much of the gain in D's unittest blocks go away.
>>
>> And no, the fact that I link libraries into the helper executable
>> doesn't mean that I can just write the unit tests in the libraries in
>> the first place. Doing so would require building them twice: Once for
>> the normal build and once for the "tester" executable.
>>
>
> OK, that makes sense. What a test framework could do, although it's kind
> of ugly, is first copy the unittest() sections into separate test files,
> compile them and then link with the tested module code.
> You would keep the advantage of having test code close to source code,
> and still compile the real code without -unittest switch.
>
>> (And yes, build times matter when your project gets large enough, even
>> in D.)
>
> Just for information, how big is your project (how many files), and how
> long does a full build take ? I have no idea how fast the compiler
> really is (is it GDC or DMD you are using ?).

I don't have a clone of my repo from where I am now, so I can't count, but it usually takes around ~30 seconds with DMD, ~2 minutes with GDC.

-- 
- Alex
April 30, 2012
On 30-04-2012 08:37, jerro wrote:
>> Sorry, I managed to get myself confused here. What I meant to say was
>> that I think >> should do an arithmetic shift if the operands are
>> signed; unsigned shift otherwise.
>
> It does arithmetic shift if the left operand is signed,
> unsigned shift otherwise. This code:
>
> void main()
> {
> int a = 0xffffffff;
> uint b = a;
> writefln("%x", a >> 1);
> writefln("%x", b >> 1);
> }
>
> prints
>
> ffffffff
> 7fffffff
>

The documentation disagrees: http://dlang.org/expression.html#ShiftExpression

It claims that it always does arithmetic shift and >>> always does unsigned shift.

-- 
- Alex
April 30, 2012
On Mon, Apr 30, 2012 at 11:46:09AM +0400, Dmitry Olshansky wrote:
> On 30.04.2012 9:33, H. S. Teoh wrote:
[...]
> >I think the latter area has lots of room for improvement. From a theoretical standpoint, syntax like [1,2,3,4,5] really should not be prematurely tied to a specific type: at the most fundamental level, it's just specifying a list of things. How the abstract concept of a list of things should be implemented need not be constrained to concrete built-in types; I'd argue that the language should permit the realization of the concept in a user-defined type as well (i.e., the literal interpreted by a user type).
> >
> >Just off the top of my head, this might be achievable by introducing a fromList method in user-defined types that takes a compile-time parameter containing some representation of the list, say as a builtin array. This method then does whatever is needed to create an instance of the type accordingly. (Since the parameter is compile-time, this essentially just generates code to create the custom container directly.)
[...]
> *cough* initializer lists *cough*
> 
> Seriously let AA liters be an sorted initializer list (conceptual compile-time array) of pairs, and normal array literal just plain initializer list of common type.
> 
> This also nails nicely strange use case of AA literal to build array
> (just the same sorted table of pairs!).  The AA then is just
> initialized with sorted array at run-time. (as it does anyway)
[...]

+1, this is an excellent idea!

It also solves the case of byte[], uint[], int[], etc., all being initializable by "[1,2,3]". Currently, subtle bugs are introduced in certain contexts by the compiler interpreting [1,2,3] to be int[] by default. What we really should do is to pass it in as a compile-time initializer list to the relevant ctors. So byte[].this() will interpret [1,2,3] as bytes, uint[].this() will interpret it as uints, etc..  Then you can write:

	uint[] a = [
		2: 100,
		10: 200
	]

and it will be equivalent to:

	uint[] a = [0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 200];


T

-- 
The most powerful one-line C program: #include "/dev/tty" -- IOCCC
April 30, 2012
On 30-04-2012 01:41, bearophile wrote:
> Walter:
>
>> What's your list?
>
> This thread now has something like 240 answers (and probably few more
> will come), and despite some variability in the answers, we have seen
> several recurring patterns too. So what are the conclusions, take-home
> insights, and the to-do's to make something in practice, from Walter &
> Andrei?
>
> Bye,
> bearophile

I think the one thing there is universal agreement on is that the comma operator has to go.

-- 
- Alex
April 30, 2012
On 30-04-2012 09:58, Jacob Carlborg wrote:
> On 2012-04-30 04:41, Jonathan M Davis wrote:
>
>> Ideally though, there would be zero difference between using a
>> property and a
>> public member variable save for taking its address (which should
>> probably just
>> be illegal for @property functions). I've been tempted to add an
>> enhancement
>> request for putting @property on public member variables to make it so
>> that
>> anything which would would break code if it were switched to a property
>> function wouldn't be legal (such as taking its address).
>> Unfortunately, right
>> now that would include stuff like ++.
>>
>> - Jonathan M Davis
>
> I would rather have @property on instance variables be a syntax sugar
> for implementing property functions. Basically virtual instance variables.
>

Then there better be a way to mark them final too. ;)

-- 
- Alex
April 30, 2012
On Mon, Apr 30, 2012 at 10:21:23AM +0200, bearophile wrote:
> H. S. Teoh:
> 
> >I think the correct solution here is to use alias. (If that doesn't work, then it should be made to work. It's a lot cleaner and doesn't introduce potentially nasty ambiguities into code,
> 
> What ambiguities?
[...]

When you have nested with's.

Or when the object members shadow local variables in the parent scope.

	struct S {
		int x;
	}

	void main() {
		int x, y;
		S s;

		with(s) {
			x = 1;
			y = 2;
		}
	}

Technically it's unambiguous which symbols are being referred to, but it makes the code hard to read because casual scanning will usually get it wrong. Plus, you're entirely at the mercy of the definition of S. If it's an imported object from an external library, for example, then when upstream makes changes to their struct/class there's a risk of introducing subtle errors into existing, correct code (by suddenly interpreting an identifier differently). This is never good.

It gets worse with nested with's: when any object being with'd changes, you risk identifier collision. The worst thing is that this can happen just by upstream(s) changing object definitions, with no change in user code.


T

-- 
Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".