April 30, 2012
On 2012-04-30 05:45, H. S. Teoh wrote:

> While personally, I like the idea of being able to create new infix
> operators, it will cause too big a change to D syntax, and probably
> cause lots of breakages with existing code, as well as make the
> lexer/parser much harder to implement (given the existing D features).
>
> You also then have to deal with operator precedence between arbitrary
> user-defined operators, which is non-trivial in general (though it's
> workable if you impose some constrains -- but it's probably way beyond
> the scope of D2 or even D3).

Yes, a language would basically need to be designed with this in mind from the start. That's what I'm thing sometimes, D could have gone down some other road in some cases but it's way too late to change it now.

-- 
/Jacob Carlborg
April 30, 2012
On 2012-04-30 05:16, Alex Rønne Petersen wrote:
> On 30-04-2012 05:03, H. S. Teoh wrote:
>> On Sun, Apr 29, 2012 at 11:39:02PM +0200, deadalnix wrote:
>>> Le 29/04/2012 22:54, Alex Rønne Petersen a écrit :
>>>> D unit tests were never really useful for anything beyond
>>>> single-library projects IMHO. They don't scale for large, real-world
>>>> application projects with lots of libraries and executables.
>>>>
>>>
>>> +1 A good std.unittest + attributes is probably a better approach.
>>
>> The only reason I actually write unittests for D code is because
>> unittest{} is so convenient. If I had to import std.unittest, most
>> likely my code will have no unittests at all.
>>
>> I find that because unittest{} makes it so convenient to write
>> unittests, it's just embarrassing to not write them. Which is kinda the
>> point, 'cos in my experience the act of writing a unittest automatically
>> makes you think about corner cases in the code you just wrote (or just
>> about to write), which means there will be less bugs from the get-go.
>>
>> Also, unittest is just that: for _unit_ tests. If you start needing an
>> entire framework for them, then you're no longer talking about _unit_
>> tests, you're talking about module- or package-level testing frameworks,
>> and you should be using something more suitable for that, not unittest.
>>
>>
>> T
>>
>
> 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.
>
> (And yes, build times matter when your project gets large enough, even
> in D.)
>


-- 
/Jacob Carlborg
April 30, 2012
On 2012-04-30 12:29, Manu wrote:
> On 30 April 2012 10:39, Jacob Carlborg <doob@me.com
>     That's the only thing I used the with-statement for.
>
>
> That's the only thing I was aware it did ;) .. are there other uses?

You can use it to access members without a receiver as well:

class Foo
{
    int x;
    int y;
}

auto foo = new Foo;

with (foo)
{
    x = 3;
    y = 4;
}

http://dlang.org/statement.html#WithStatement

-- 
/Jacob Carlborg
April 30, 2012
Le 30/04/2012 04:34, H. S. Teoh a écrit :
> On Sun, Apr 29, 2012 at 11:18:12PM +0200, deadalnix wrote:
> [...]
>> C don't have out parameters as D have. C have pointer to do kind of
>> out parameters, and D have pointers too, this is a non issue.
>
> I argue that using 'out' vs. a pointer is a good thing, because it
> clarifies intent. When you see a pointer, it's far from clear whether
> it's an input parameter, an output parameter, or both.
>
> More and more, I'm leaning towards the opinion that all code should
> reveal intent, preferably in a language-supported way. Unclear intent is
> what leads to subtle bugs caused by people calling functions with wrong
> assumptions. (You'd think this should be a non-problem with programmers,
> who are presumably smart enough to figure things out without being told
> in the face, but I've seen too much "enterprise" code by now to not be
> cynical about it.)
>
>
> T
>

I do agree. However, I don't think this apply in any way to our case. out parameter is a C usage, and it is confusing in C, because, as you mentioned, you don't know if you pass the pointer because it is an out parameter, because you want to avoid copy, because something else . . .

The fact that better constructs (ie Tuples) exists in D make it already clear. And if the point is to fix C, it is useless because the whole thing is already confusing in C.
April 30, 2012
Le 30/04/2012 11:17, SomeDude a écrit :
> On Monday, 30 April 2012 at 02:33:35 UTC, H. S. Teoh wrote:
>> On Sun, Apr 29, 2012 at 11:18:12PM +0200, deadalnix wrote:
>> [...]
>>> C don't have out parameters as D have. C have pointer to do kind of
>>> out parameters, and D have pointers too, this is a non issue.
>>
>> I argue that using 'out' vs. a pointer is a good thing, because it
>> clarifies intent. When you see a pointer, it's far from clear whether
>> it's an input parameter, an output parameter, or both.
>>
>> More and more, I'm leaning towards the opinion that all code should
>> reveal intent, preferably in a language-supported way. Unclear intent is
>> what leads to subtle bugs caused by people calling functions with wrong
>> assumptions. (You'd think this should be a non-problem with programmers,
>> who are presumably smart enough to figure things out without being told
>> in the face, but I've seen too much "enterprise" code by now to not be
>> cynical about it.)
>>
>>
>> T
>
> Of course, a better way would be to change the meaning of the comma
> operator to allow a Python-style syntax for return values, i.e something
> like
>
> int, Error foo(char[] input, ref Bar){...}
>
> auto res, err = foo(input, bar);
>

Exactly.

> We would then only allow in and inout parameters. This would be much
> closer to functional style. There would be no longer any need for the
> "in" and "out" keywords.
> If we push a little further, you can also get rid of inout by doing this:
>
> int, ref Bar foo(char[] input, ref Bar){...}
> auto out, bar = foo(input, bar);
>
> Every time the compiler sees the same symbol as an input and output
> parameter, it can assume it's an inout parameter. This, of course, would
> break a lot of code.

It isn't a good idea.
April 30, 2012
Le 30/04/2012 04:52, H. S. Teoh a écrit :
> On Sun, Apr 29, 2012 at 10:03:43AM +0400, Dmitry Olshansky wrote:
>> On 29.04.2012 5:06, bearophile wrote:
> [...]
>>> Loops _must_ be fully efficient, they are a basic language construct,
>>> this is very important. Even foreach() is sometimes not equally
>>> efficient as a for() in some cases...
>>>
>> Doesn't have to do anything with the LANGUAGE.
>> Yesterday I tried GDC. Damn I didn't regret it :)
> [...]
>
> Unfortunately, even GDC doesn't inline opApply and its delegate for the
> simplest of loops:
>
> 	struct S {
> 		int data[];
> 		int opApply(int delegate(ref int) dg) {
> 			foreach (d; data) {
> 				if (auto r = dg(d))
> 					return r;
> 			}
> 			return 0;
> 		}
> 	}
> 	void main() {
> 		S s;
> 		foreach (e; s) {
> 			writeln(e);
> 		}
> 	}
>
> I think it's because the front-end always generates the full delegate
> passing code without inlining anything. IMO, this case *need* to be
> aggressively inlined in order to make D's generic programming
> capabilities a stronger selling point.
>
>
> T
>

It is an implementation issue (a real and serious one, but still). It should be fixed by implementation, not language design.
April 30, 2012
Le 29/04/2012 23:54, Peter Alexander a écrit :
> On Sunday, 29 April 2012 at 21:18:40 UTC, deadalnix wrote:
>> Le 29/04/2012 03:06, bearophile a écrit :
>>> Jonathan M Davis:
>>>
>>>> * foreach_reverse is essentially redudant at this point (not to mention
>>>> confusing if combined with delegates), since we have retro.
>>>
>>> retro() can't replace foreach_reverse until the front-end
>>> demonstrability produces asm code equally efficient.
>>> Loops _must_ be fully efficient, they are a basic language construct,
>>> this is very important. Even foreach() is sometimes not equally
>>> efficient as a for() in some cases...
>>>
>>
>> This is an implementation issue and shouldn't be an argument for
>> language design.
>
> The 'sufficiently smart compiler' argument is old and invalid. Please do
> not use it.
>

This is a case by case issue. You should consider fixing implementation issue with implementation, and consider language design if that first one fail. If you don't think this is right, the only rational solution you have is to use assembly directly.

As you fail to show how this is something that isn't reasonably implementable, you have no argument.
April 30, 2012
Le 30/04/2012 05:03, H. S. Teoh a écrit :
> On Sun, Apr 29, 2012 at 11:39:02PM +0200, deadalnix wrote:
>> Le 29/04/2012 22:54, Alex Rønne Petersen a écrit :
>>> D unit tests were never really useful for anything beyond
>>> single-library projects IMHO. They don't scale for large, real-world
>>> application projects with lots of libraries and executables.
>>>
>>
>> +1 A good std.unittest + attributes is probably a better approach.
>
> The only reason I actually write unittests for D code is because
> unittest{} is so convenient. If I had to import std.unittest, most
> likely my code will have no unittests at all.
>

Is @unittest on top of a function much more difficult ?

> I find that because unittest{} makes it so convenient to write
> unittests, it's just embarrassing to not write them. Which is kinda the
> point, 'cos in my experience the act of writing a unittest automatically
> makes you think about corner cases in the code you just wrote (or just
> about to write), which means there will be less bugs from the get-go.
>

Agreed.

> Also, unittest is just that: for _unit_ tests. If you start needing an
> entire framework for them, then you're no longer talking about _unit_
> tests, you're talking about module- or package-level testing frameworks,
> and you should be using something more suitable for that, not unittest.
>

Consider cases like checking if Liskov substitution principle is fallowed in a class hierarchy running the same unitest on various instantiations in that hierarchy.

This is common need and still fall in the unittest bag.
April 30, 2012
Le 30/04/2012 06:20, H. S. Teoh a écrit :
> On Mon, Apr 30, 2012 at 01:57:58AM +0200, Alex Rønne Petersen wrote:
>> On 30-04-2012 01:54, Era Scarecrow wrote:
>>> On Sunday, 29 April 2012 at 15:07:26 UTC, David Nadlinger wrote:
>>>> On Sunday, 29 April 2012 at 14:40:38 UTC, Jacob Carlborg wrote:
> [...]
>>>> We'd still need a solution for continue and break, though.
>>>
>>> A thought coming to mind regarding this, is a special exception. If
>>> the compiler recognizes it's part of a foreach (or other loop) then
>>> continue gets converted to return, and and break throws an exception
>>> (caught by the foreach of course)
>>>
>>> But that involves more compiler magic.
>>>
>>
>> And forced EH which is unacceptable in e.g. a kernel.
> [...]
>
> Here's a wild idea: introduce the concept of the multi-return function
> (or, in this case, delegate). Unlike normal functions which returns to a
> single point when they end, usually by pushing the return address onto
> the runtime stack, a multi-return function is called by pushing
> _multiple_ return addresses onto the runtime stack. The function body
> decides which return address to use (it can only use one of them).
>
> Implementing break/continue then can be done like this: the loop body
> delegate will be a multi-return delegate, i.e., a delegate whose caller
> will provide multiple return addresses: one for each possible
> break/continue point.  For example:
>
> 	outerLoop: foreach (a; containerA) {
> 		innerLoop: foreach (b; containerB) {
> 			if (condition1())
> 				continue outerLoop;
>
> 			if (condition2())
> 				break /* innerLoop */;
>
> 			if (condition3())
> 				break outerLoop;
> 		}
> 		if (condition4())
> 			break /* outerLoop */;
> 	}
>
> When containerA.opApply is called, it calls the outer loop body with two
> return addresses: the first is the usual return address from a function
> call, the second is the cleanup code at the end of opApply that performs
> any necessary cleanups and then returns. I.e., it simulates break. So
> when condition4 triggers, the outerLoop delegate returns to the second
> address.
>
> Now the outerLoop delegate itself calls containerB.opApply with a list
> of outer loop return addresses, i.e., (1) return to containerA.opApply's
> caller, that is, break outerLoop, (2) return to outerLoop delegate's
> cleanup code, i.e. continue OuterLoop. Then containerB.opApply prepends
> two more return addresses to this list, the usual return address to
> containerB.opApply, and its corresponding break return (prepend because
> the last return addressed pushed must correspond with the immediate
> containing scope of the called delegate, but if the delegate knows about
> outer scopes then it can return to those).
>
> Now the innerLoop delegate has four return addresses: return to
> containerB.opApply normally (continue innerLoop), return to
> containerB.opApply's cleanup code (break innerLoop), return to
> containerA.opApply normally (continue outerLoop), and return to
> containerA.opApply's cleanup code (break outerLoop). So break/continue
> works for all cases.
>
> (Of course, containerB.opApply doesn't actually just prepend return
> addresses to what the outerLoop delegate passes in, since when the
> innerLoop delegate wants to break outerLoop, it needs to cleanup the
> stack frames of the intervening call to containerB.opApply too. So
> containerB.opApply needs to insert its own cleanup code into the return
> address chain.)
>
> This is, at least, the *conceptual* aspect of things. In the actual
> implementation, the compiler may use the current scheme (return an int
> to indicate which return is desired) instead of doing what amounts to
> reinventing stack unwinding, but the important point is, this should be
> transparent to user code. As far as the user is concerned, they just
> call the delegate normally, no need to check return codes, etc., with
> the understanding that the said delegates have multiple return
> addresses. The compiler inserts the necessary scaffolding, checking for
> int returns, etc., to actually implement the concept.
>

This make sense. This seems to me like the way to go.
April 30, 2012
Le 30/04/2012 05:12, Kapps a écrit :
> On Monday, 30 April 2012 at 01:08:28 UTC, Jonathan M Davis wrote:
>> On Sunday, April 29, 2012 17:50:48 Don wrote:
>>> * package. I have no idea how a failed Java experiment got incorporated
>>> into D.
>>
>> Really? In some cases, it's indispensable. For instance, once
>> std.datetime has
>> been split up, it will require it, or it would have duplicate a bunch of
>> implementation-specific stuff which has no business in the public API.
>>
>> - Jonathan M Davis
>
> It's entirely dependent on your coding style. For example, when you look
> at Phobos you rarely (if ever?) see package functions. This is because
> it's entirely module based with a strong degree of separation between
> modules.
>
> However, for someone coming from C#, removing package would be awful. I
> personally use package quite often. For the most part, I stick to one
> major class per file, and separate things across library. There are
> plenty of things that I want other classes in the package/static-library
> to use, but don't want to expose to the public, and thus use package for.

Phobos is a really good example. Modules tend to become more and more fat. And to split them up, package is mandatory.