Re: build Ldc2 for win xp 32 bit Error

2012-07-31 Thread Don Clugston

On 26/07/12 09:05, Jacob Carlborg wrote:

On 2012-07-25 22:39, Rainer Schuetze wrote:


What is the state of the missing exception handling for Windows?


I just read an old post on the Clang mailing list, it's not looking
good. It seems Microsoft (or someone else) has a patent on SEH,


I've heard this, but does anyone know what patent is being referred to? 
Several times I've heard mention of an old one by Borland, which 
Microsoft bought. The Borland patent is not a patent on SEH, it's 
basically a patent on using a thunk. I suspect it is extremely unlikely 
to be a valid patent, for sure there is prior art. And the only reason 
for implementing it with a thunk anyway, is as a workaround for the 
broken thread-local support in Windows prior to Vista.


It's not difficult to implement SEH without violating that patent (which 
is due to expire soon anyway). Is there some other patent that people 
are referring to?



which

basically means: never gonna happen. An alternative could be
setjmp/longjmp. On 64bit it looks a bit better, where the correct way
seems to be to use the Win64 exception ABI.


Win64 SEH is scarcely any different to Win32 SEH, it's just better 
documented. You can do the same thing on Win32.




http://clang-developers.42468.n3.nabble.com/LLVM-Clang-and-setjmp-longjmp-exception-handling-on-MinGW-td3407322.html


http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx


The situation makes no sense to me.



Re: BitArray/BitFields - Review

2012-07-31 Thread Don Clugston

On 29/07/12 23:36, bearophile wrote:

Era Scarecrow:


 Another commonly needed operation is a very fast bit count. There 
are very refined algorithms to do this.



 Likely similar to the hamming weight table mentioned in TDPL.
Combined with the canUseBulk I think I could make it fairly fast.


There is lot of literature about implementing this operation
efficiently. For the first implementation a moderately fast (and short)
code is probably enough. Later faster versions of this operation will go
in Phobos, coming from papers.


See bug 4717. On x86, even on 32 bits you can get close to 1 cycle per 
byte, on 64 bits you can do much better.


Re: Pull freeze

2012-07-30 Thread Don Clugston

On 29/07/12 13:43, Robert Clipsham wrote:

On Sunday, 29 July 2012 at 06:08:18 UTC, Andrei Alexandrescu wrote:

Due to the upcoming release, there will be no regular pull
walk-through tomorrow. Thanks for the growing rate of contribution,
and let's resume the ritual next Sunday.

Andrei


I really can't shake the feeling that you guys just don't get git!

You never need to freeze pulls with git. Ever! It just slows down
development.

The work flow is simple enough:

1. Time for a release
2. Create a release branch, it is feature frozen
3. You can keep pulling feature into master, no problem
4. You can pull regression/bug fixes into the release branch
5. A release is made, merge the release branch into master and continue.

I don't know why I bothered typing this out - the discussion has been
had time and time again with no progress made.


From a technical point of view, I think the main thing to be done 
relates to the auto-tester.
We want the autotester to run on the release branch, as well as the 
development branch.


Note of course that we have druntime and Phobos as well as DMD; they all 
need their own release branches.
I guess the easiest way to do this would be to have a single, permanent 
branch called 'release', that is used for all releases, rather than 
creating a release branch for each compiler version.


Re: std.variant benchmark

2012-07-30 Thread Don Clugston

On 30/07/12 13:24, Andrei Alexandrescu wrote:

On 7/30/12 4:34 AM, Dmitry Olshansky wrote:

On 30-Jul-12 06:01, Andrei Alexandrescu wrote:

In fact memcpy could and should be replaced with word by word copy for
almost all of struct sizes up to ~32 bytes (as size is known in advance
for this particular function pointer i.e. handler!int).


In fact memcpy should be smart enough to do all that, but apparently it
doesn't.



I'd say array ops could and should do this (since compiler has all the
info at compile-time). On the other hand memcpy is just one tired C
function aimed at fast blitting of any memory chunks.
(Even just call/ret pair is too much of overhead in case of int).


memcpy is implemented as an intrinsic on many platforms. I'm not sure
whether it is on dmd, but it is on dmc
(http://www.digitalmars.com/ctg/sc.html), icc, and gcc
(http://software.intel.com/en-us/articles/memcpy-performance/). But then
clearly using simple word assignments wherever possible makes for a more
robust performance profile.


It is an intrinsic on DMD, but it isn't done optimally. Mostly it just 
compiles to a couple of loads + the single instruction

rep movsd; / rep movsq;
which is perfect for medium-sized lengths when everything is aligned, 
but once it is longer than a few hundred bytes, it should be done as a 
function call. (The optimal method involves cache blocking).

Also for very short lengths it should be done as a couple of loads.


Re: One against binary searches

2012-07-30 Thread Don Clugston

On 30/07/12 17:40, bearophile wrote:

This author writes very detailed analyses of low-level computational
matters, that appear on Reddit. This blog post he suggests to introduce
offseted binary or quaternary search instead of binary search in
Phobos:

http://www.pvk.ca/Blog/2012/07/30/binary-search-is-a-pathological-case-for-caches/


Bye,
bearophile


Fantastic article, thanks!
The fact that physical addressing can influence L2 cache misses was 
completely new to me.


Re: FYI my experience with D' version

2012-07-30 Thread Don Clugston

On 30/07/12 14:32, Jacob Carlborg wrote:

On 2012-07-30 12:30, torhu wrote:


version is good for global options that you set with -version on the
command line.  And can also be used internally in a module, but doesn't
work across modules.  But it seems you have discovered this the hard way
already.

I think there was a discussion about this a few years ago, Walter did it
this way on purpose.  Can't remember the details, though.


He probably wants to avoid the C macro hell.




IIRC it's because version identifiers are global.

__
module b;
version = CoolStuff;
__

module a;
import b;
version (X86)
{
   version = CoolStuff;
}

version(CoolStuff)
{
   // Looks as though this is only true on X86.
   // But because module b used the same name, it's actually true always.
}
__

These types of problems would be avoided if we used the one-definition 
rule for version statements, bugzilla 7417.

















Re: Computed gotos on Reddit

2012-07-26 Thread Don Clugston

On 26/07/12 00:46, Walter Bright wrote:

On 7/25/2012 2:55 PM, Dmitry Olshansky wrote:

std\regex.d(5118): Error: undefined identifier 'L_jumptable'



I was afraid of that. You may have to approximate it by loading the
address of L_jumptable into a register and adding it in instead of
using
the addressing mode.


I failed to load it in any register or interact with it in any way.
I think I've stalled. There has to be a way to get label address
somehow, I got
tired of guess and shot :(

BTW that would allow us to do computed gotos but only in inline asm.



How to get an address:

  call jump_table
L1:

  ...
jump_table:
  pop EAX
  jmp L1
  .. the rest of the jump table ...

Yes, it's awful, but we're just trying to take some measurements here,
so it doesn't matter.

What I meant was add these extra instructions in to the switch version
as dummies in order to make the extra time they take irrelevant to
looking at the difference.


But doing that screws up the CPUs stack prediction so badly that it 
will dominate the timing

At least do something like:

jump_table:
  move EAX, [ESP]
  ret




Re: Coming Soon: Stable D Releases!

2012-07-25 Thread Don Clugston

On 25/07/12 14:32, Jacob Carlborg wrote:

On 2012-07-25 09:43, Don Clugston wrote:


We don't need this complexity. The solution is *trivial*. We just need
to decide in advance that we will target a release every X weeks, and
that it should be delayed only for reasons of stability.


Yeah, but what happens when Walter or someone else decides to start a
big project, i.e. implementing COFF support, a week before release? We
end up with a bunch of half finished things.


If we had an agreed release cycle, it would not happen. The release 
cycle would be a higher authority than any single person, even Walter.



A solution to this would be to create a new branch or not push the
changes upstream. Although I don't understand why Walter doesn't already
do this.


An agreement is ALL that is required. But despite repeated requests, I
have never been able to get any traction on the idea.
Instead, people propose all kinds of crazy technical solutions, the most
recent ones being changes to bugzilla, trello, and now dlang-stable.

If we say, There will be a new compiler release every 8 weeks, the
problem is solved. Seriously. That one-off agreement is ALL that is
required.


Apparently it seems very difficult to agree upon, since it hasn't
happened. The releases just pop up at random.


I have tried many times, without success. I've never succeeded in 
getting more than two or three people interested.







Re: Computed gotos on Reddit

2012-07-25 Thread Don Clugston

On 25/07/12 09:37, Walter Bright wrote:

On 7/24/2012 11:46 PM, Dmitry Olshansky wrote:

It's pc = address because one can first preprocess all of byte code
doing
opcode = address rewrites. But you can't do it unless taking address
of labels
is possible.


All right, that's the piece that was missing.

I suppose it is possible for the compiler to recognize that the
opcode=address array is invariant, and optimize it out, but that would
be a novel optimization. I don't know how hard it would be.


  Done: http://d.puremagic.com/issues/show_bug.cgi?id=8431

Thanks!


Another interesting optimization with final switch would be if each 
case has about the same code length.


final switch(x) {
case C1:  ...
case C2:  ...
case C3:  ...
case C4:  ...
}
then if (case c2) - (case C1) == (case C3) - (case C2)

change it to
goto (case C1) + x *( (case c2) - (case C1) );

so that there is no lookup table, just a multiply.


Re: Computed gotos on Reddit

2012-07-25 Thread Don Clugston

On 25/07/12 09:55, Dmitry Olshansky wrote:

On 25-Jul-12 11:51, Don Clugston wrote:

On 25/07/12 09:37, Walter Bright wrote:

On 7/24/2012 11:46 PM, Dmitry Olshansky wrote:

It's pc = address because one can first preprocess all of byte code
doing
opcode = address rewrites. But you can't do it unless taking address
of labels
is possible.


All right, that's the piece that was missing.

I suppose it is possible for the compiler to recognize that the
opcode=address array is invariant, and optimize it out, but that would
be a novel optimization. I don't know how hard it would be.


  Done: http://d.puremagic.com/issues/show_bug.cgi?id=8431

Thanks!


Another interesting optimization with final switch would be if each
case has about the same code length.

final switch(x) {
case C1:  ...
case C2:  ...
case C3:  ...
case C4:  ...
}
then if (case c2) - (case C1) == (case C3) - (case C2)

change it to
goto (case C1) + x *( (case c2) - (case C1) );

so that there is no lookup table, just a multiply.


Could be interesting if some other simple progressions could be
hardcoded, if say branches are be sorted by length.


Ooh, that's an interesting idea too.


Also modern CPU seem
to be exceptionally fast at skipping NOPs so a bit of padding won't hurt.


And an unconditional branch takes no time (only one 1 uop) on modern 
CPUs too.





Re: Troubles with immutable arrays

2012-07-25 Thread Don Clugston

On 23/07/12 15:29, bearophile wrote:

After a discussion in D.learn started by someone else, after a
suggestion of mine Timon Gehr has added a bug report:

http://d.puremagic.com/issues/show_bug.cgi?id=8400

But the bug was fixed in the opposite way of what I was thinking.

The problem was that the length of global immutable arrays arrays is
seen as a compile-time constant.
Instead of fixing that, Issue 8400 has done the opposite, now even the
lenght of local immutable arrays is seen sometimes as a compile-time
constant, and example:


Sorry bearophile, I completely disagree with this post.

Currently, when a compile time value is required, CTFE is attempted. If 
it fails, an error message is generated.


You are asking for a corner case to be introduced. Under certain 
circumstances (which aren't clearly defined), you want CTFE to *not* be 
attempted.



 immutable int[] A = foo(5);
 int[A.length] B;



This code too compiles, so A is sometimes computed at run-time and
sometimes at compile-time:


  immutable int[] A = foo(n);


Now immutable arrays are sometimes seen as enums.


That is not correct, an immutable array is always different to an enum. 
For example, an enum is simply a manifest constant, and does not have an 
address. An immutable array always has an address.



I think this is a
problem. I think in D compile-time is run only if it's evaluated in a
context where compile-time values are required. But now the situation is
more muddy, because knowing n at compile-time is not a way to ask A to
be computed at compile-time.


The only consequence is that if you don't require it at compile time, a 
particular optimization might not happen. There is no change to semantics.



Another problem is that compile-time arrays in many situations are not
efficient, they gets copied every time you use them, and I think that
__d_arrayliteralTX performs a heap allocation. So now both enum and
immutable arrays perform heap allocations every time you use them, but
only in some situations.


That's the famous bug 2356, which is completely irrelevant to this 
situation.



I think this is a messy situation, I think the fix for bug 8400 should
be undone, and I think Issue 8400 should be fixed the other way, turning
global immutable arrays too into run-time entities.


Did you even know that initializers of global variables, including 
arrays, including even mutable arrays, are ALWAYS CTFE'd?





Re: Computed gotos on Reddit

2012-07-25 Thread Don Clugston

On 25/07/12 12:11, Walter Bright wrote:

On 7/25/2012 12:51 AM, Don Clugston wrote:

so that there is no lookup table, just a multiply.


Rethinking your idea a bit...

Suppose the switch jump_address[] array was really an array of hardcoded
jmp instructions, 5 bytes each:

   jmp_table:
 jmp Lcase1;
 jmp Lcase2;
 jmp Lcase3;
 ...

and then the switch(EBX) would be:

 lea EAX,jmp_table[EBX][EBX*4]
 jmp EAX

is that kick-ass or what?

(There'd be some additional complication for PIC code.)


Very nice. The jumps in the jump table take effectively zero cycles. 
That looks quite doable.






Re: Semantics of postfix ops for classes

2012-07-25 Thread Don Clugston

On 20/07/12 17:12, Andrej Mitrovic wrote:

According to TDPL postfix operators are rewritten to call prefix
operators, e.g. on this call for some user-type object named a:

auto b = a++;

// is converted to:
auto b = ((ref x) { auto t = x; ++x; return t; })(a);

But I don't see how this is reasonable for classes. Examine:

struct Struct {
 int x = 1;
 Struct opUnary(string op : ++)() {
 x++;
 return this;
 }
}

class Class {
 int x = 1;
 Class opUnary(string op : ++)() {
 x++;
 return this;
 }
}

void main()
{
 Struct foo1;
 Struct foo2 = foo1++;
 assert(foo1.x != foo2.x);  // ok

 Class bar1 = new Class;
 Class bar2 = bar1++;
 assert(bar1.x != bar2.x);  // fail
}

It's clear why, the rewrite that calls auto t = x simply binds
another reference to the same object.

Unfortunately this makes it hard to wrap C++ libraries which have both
prefix/postfix operators defined. Currently I wrap these in e.g.
preInc/postInc methods and I explicitly disable the prefix/postfix
opUnary methods.

Are the semantics of this rewrite ok with people who use op overloads?
I found them to be surprising, but then again I don't use op overloads
that much, I'm just noticing the difference between C++ and D.


But classes have reference semantics, so they are already completely 
different from C++.


The question really is, do postfix ++ and -- make sense for reference 
types? Arguably not. From a theoretical sense, the existing behaviour 
does make sense, but in practice, every time it is used, it is probably 
a bug.


The only other reasonable option I can think of would be to make class++ 
be of type void, so that you could still write

bar1++;
but not bar2 = bar1++;
since the existing behaviour can be achieved by writing bar2 = ++ bar1;





Re: Coming Soon: Stable D Releases!

2012-07-24 Thread Don Clugston

On 16/07/12 09:51, Adam Wilson wrote:

As a result of the D Versioning thread, we have decided to create a new
organization on Github called dlang-stable. This organization will be
responsible for maintaining stable releases of DMD, DRuntime, and Phobos.

So what is a stable release?
A stable release is a complete build of DMD, DRuntime, and Phobos that
ONLY includes the latest bug-fixes and non-breaking enhancements to
existing features. It will not include, new features, breaking
enhancements, and any other code that the core development team may be
working on.


I'm not actually sure what this means. I fear that it may be motivated 
by an inaccurate assessment of the current situation.


The existing instability comes almost entirely from Phobos, not from the 
compiler. Historically there have been very few instances where you 
might want to choose an older compiler in preference to the latest release.


As I've said before, the one time when a language change caused 
*massive* instability was in the attempt to move AAs from language to 
library -- even though that wasn't even supposed to affect existing code 
in any way. The other thing that typically causes regressions is fixes 
to forward-reference bugs.


Historically, addition of new language features has NOT caused 
instability. What has been true is that features have been added to the 
compiler before they were really usable, but they have not broken 
existing code. Fairly obviously the 64 bit compiler was quite buggy when 
initially released. But even that massive change wasn't much more buggy 
than the library AAs! So I am not sure that you can correctly guess 
where instability will come from.


In summary -- I would not expect your stable DMD to be very different 
from the normal DMD. Phobos is where the instability issue is.


Re: feature request: with(var decl) {}

2012-07-24 Thread Don Clugston

On 23/07/12 17:04, Adam D. Ruppe wrote:

On Monday, 23 July 2012 at 14:46:30 UTC, FeepingCreature wrote:

The more general form would be to make variable declaration an
expression.


Right, and that would be pretty amazing, but it would probably
be too hard to do in D today...



The bizarre thing, however, is that the compiler uses it internally. 
There's thing called a DeclarationExp. It's created all the time when 
lowering occurs.

Its only in the parser that declarations are not valid as expressions.



Re: D versionning

2012-07-16 Thread Don Clugston

On 16/07/12 16:51, David Nadlinger wrote:

On Monday, 16 July 2012 at 06:00:03 UTC, Walter Bright wrote:

Supporting Win64 is absolutely critical for the future of D, and the
sooner we get it, the better. The COFF route is the shortest route to
doing it, and the most practical for attracting devs, which is why
it's the way we're going.


Sorry, but I don't think this is a valid argument. Yes, Win64 (and even
more so, COFF) support is important to have for DMD, but no, it's not a
good idea to delay a pending release because of this (cf. the »Time for
a new beta« thread from the end of May). Here is why:

http://d.puremagic.com/issues/buglist.cgi?chfieldto=Nowquery_format=advancedchfield=bug_statuschfieldfrom=2012-04-13bug_status=RESOLVEDresolution=FIXED


Already 289 issues resolved since 2.059!


More than that. Of the official releases, there is no usable 64 bit DMD 
compiler on ANY platform. Some awful wrong-code bugs were still present 
in 2.059. They have been fixed for a couple of months in DMD git, but 
not in an official release.


Re: Why is std.algorithm so complicated to use?

2012-07-16 Thread Don Clugston

On 10/07/12 16:59, Andrei Alexandrescu wrote:

On 7/10/12 9:59 AM, H. S. Teoh wrote:

On Tue, Jul 10, 2012 at 09:28:51AM -0400, Andrei Alexandrescu wrote:

On 7/10/12 2:50 AM, Jacob Carlborg wrote:

On 2012-07-09 22:16, Andrei Alexandrescu wrote:


So foo is a range of strings, because each element of it is a
string.  Then you want to chain a range of strings with a string,
which is a range of dchar. That doesn't work, and I agree the error
message should be more informative.


Is that by design or something that can be fixed?


We can arrange things in the library that a custom message is issued,
or in the compiler to do it once for all.


Please don't do it in the compiler. Custom messages should be in the
library. Tying the compiler to phobos is a bad idea; druntime should be
the only dependency.


The idea there being that the compiler could give good details about
what part of a complex constraint has failed.


However the compiler doesn't know which constraint was supposed to pass.
If it is lucky enough to only have one template, it can do it, but if it 
has:

template1 if (A  B)
template2 if (C  D)
template3 if ( (E || F)  G)

should it print:
foo.d(99): Error: no matching template
foo.d(10):constraint failed: A
foo.d(28):constraint failed: D
foo.d(57):constraint failed: (E || F)
?
Could be a very long list, if there are many templates.

Determining the minimal list of constraints seems like a nice 
application for BDDs...






Re: cast from void[] to ubyte[] in ctfe

2012-07-16 Thread Don Clugston

On 13/07/12 12:52, Johannes Pfau wrote:

Am Fri, 13 Jul 2012 11:53:07 +0200
schrieb Don Clugston d...@nospam.com:


On 13/07/12 11:16, Johannes Pfau wrote:

Casting from void[] to ubyte[] is currently not allowed in CTFE. Is
there a special reason for this? I don't see how this cast can be
dangerous?


CTFE doesn't allow ANY form of reinterpret cast, apart from
signed-unsigned. In particular, you can't do anything in CTFE which
exposes endianness.

It might let you cast from ubyte[] to void[] and then back to ubyte[]
or byte[], but that would be all.


So that's a deliberate decision and won't change?
I guess it's a safety measure as the ctfe and runtime endianness could
differ?


Yes.



Anyway, I can understand that reasoning but it also means that
the new std.hash could only be used with raw ubyte[] arrays and it
wouldn't be possible to generate the CRC/SHA1/MD5 etc sum of e.g. a
string in ctfe. (Which might make sense for most types as the result
could really differ depending on endianness, but it shouldn't matter for
UTF8 strings, right?)

Maybe I can special case CTFE so that at least UTF8 strings work.

BTW: casting from void[][] to ubyte[][] seems to work. I guess this is
only an oversight and nothing I could use as a workaround?


Probably a bug.
But you can convert from char[] to byte[]/ubyte[]. That's OK, it doesn't 
depend on endianness.


Re: All right, all right! Interim decision regarding qualified Object methods

2012-07-13 Thread Don Clugston

On 13/07/12 11:02, F i L wrote:

I always wondered why toString() wasn't just to!string() in the first
place, short of UFCS not being implemented for all types.



toString() comes from the days before D had templates.


Re: D versionning

2012-07-13 Thread Don Clugston

On 13/07/12 09:11, Jacob Carlborg wrote:

On 2012-07-13 08:52, Adam Wilson wrote:


I hope Walter isn't against this, because I'm not seeing much community
disagreement with this...


If he's not against it, I see know reason why this haven't been done
already.




It has. It's called D1.





Re: cast from void[] to ubyte[] in ctfe

2012-07-13 Thread Don Clugston

On 13/07/12 11:16, Johannes Pfau wrote:

Casting from void[] to ubyte[] is currently not allowed in CTFE. Is
there a special reason for this? I don't see how this cast can be
dangerous?


CTFE doesn't allow ANY form of reinterpret cast, apart from 
signed-unsigned. In particular, you can't do anything in CTFE which 
exposes endianness.


It might let you cast from ubyte[] to void[] and then back to ubyte[] or 
byte[], but that would be all.


Re: All right, all right! Interim decision regarding qualified Object methods

2012-07-12 Thread Don Clugston

On 12/07/12 06:15, Andrei Alexandrescu wrote:

Required reading prior to this: http://goo.gl/eXpuX

You destroyed, we listened.

I think Christophe makes a great point. We've been all thinking inside
the box but we should question the very existence of the box. Once the
necessity of opCmp, opEquals, toHash, toString is being debated, we get
to some interesting points:

1. Polymorphic comparisons for objects has problems even without
considering interaction with qualifiers. I wrote quite a few pages about
that in TDPL, which add to a lore grown within the Java community.

2. C++ has very, very successfully avoided the necessity of planting
polymorphic comparisons in base classes by use of templates. The issue
is template code bloat. My impression from being in touch with the C++
community for a long time is that virtually nobody even talks about code
bloat anymore. For whatever combination of industry and market forces,
it's just not an issue anymore.

3. opCmp, opEquals, and toHash are all needed primarily for one thing:
built-in hashes. (There's also use of them in the moribund .sort
method.) The thing is, the design of built-in hashes predates the
existence of templates. There are reasons to move to generic-based
hashes instead of today's runtime hashes (such as the phenomenal success
of templated containers in C++), so it can be argued that opCmp,
opEquals, and toHash exist for reasons that are going extinct.

4. Adding support for the likes of logical constness is possible, but
gravitates between too lax and onerously complicated. Walter and I don't
think the aggravation is justified.

There are of course more angles and considerations. Walter and I
discussed such for a while and concluded we should take the following
route:

1. For the time being, rollback the changes. Kenji, could you please do
the honors? There's no need to undo everything, only the key parts in
object.d. Apologies for having to undo your work!

2. Investigate a robust migration path from the current use of opCmp,
opEquals, toHash (we need to also investigate toString) to a world in
which these methods don't exist in Object. In that world, associative
arrays would probably be entirely generic. Ideally we should allow
existing code to still work, while at the same time fostering a better
style for new code.


What say you?

Andrei


Well:
* having opCmp() defined for all objects is just plain weird.
* toString() is a poor design anyway.

But we'd need to be very careful, this is a very disruptive change.





Re: All right, all right! Interim decision regarding qualified Object methods

2012-07-12 Thread Don Clugston

On 12/07/12 12:00, Paulo Pinto wrote:

On Thursday, 12 July 2012 at 08:59:46 UTC, Don Clugston wrote:

On 12/07/12 06:15, Andrei Alexandrescu wrote:

Required reading prior to this: http://goo.gl/eXpuX

You destroyed, we listened.

I think Christophe makes a great point. We've been all thinking inside
the box but we should question the very existence of the box. Once the
necessity of opCmp, opEquals, toHash, toString is being debated, we get
to some interesting points:

1. Polymorphic comparisons for objects has problems even without
considering interaction with qualifiers. I wrote quite a few pages about
that in TDPL, which add to a lore grown within the Java community.

2. C++ has very, very successfully avoided the necessity of planting
polymorphic comparisons in base classes by use of templates. The issue
is template code bloat. My impression from being in touch with the C++
community for a long time is that virtually nobody even talks about code
bloat anymore. For whatever combination of industry and market forces,
it's just not an issue anymore.

3. opCmp, opEquals, and toHash are all needed primarily for one thing:
built-in hashes. (There's also use of them in the moribund .sort
method.) The thing is, the design of built-in hashes predates the
existence of templates. There are reasons to move to generic-based
hashes instead of today's runtime hashes (such as the phenomenal success
of templated containers in C++), so it can be argued that opCmp,
opEquals, and toHash exist for reasons that are going extinct.

4. Adding support for the likes of logical constness is possible, but
gravitates between too lax and onerously complicated. Walter and I don't
think the aggravation is justified.

There are of course more angles and considerations. Walter and I
discussed such for a while and concluded we should take the following
route:

1. For the time being, rollback the changes. Kenji, could you please do
the honors? There's no need to undo everything, only the key parts in
object.d. Apologies for having to undo your work!

2. Investigate a robust migration path from the current use of opCmp,
opEquals, toHash (we need to also investigate toString) to a world in
which these methods don't exist in Object. In that world, associative
arrays would probably be entirely generic. Ideally we should allow
existing code to still work, while at the same time fostering a better
style for new code.


What say you?

Andrei


Well:
* having opCmp() defined for all objects is just plain weird.
* toString() is a poor design anyway.

But we'd need to be very careful, this is a very disruptive change.


I don't find them that weird, because many OO languages do have them.


Really? I find that incredible. Ordered comparisons ,  don't even make 
sense for many mathematical objects!

You can't even define opCmp for a float.

Object f = new FtpConnection;
Object e = new Employee(Bob);
if (f  e)  // Huh???




Re: stdarg x86_64 problems...

2012-07-12 Thread Don Clugston

On 12/07/12 11:12, John Colvin wrote:

When I compile the following code with -m32 and -m64 i get a totally
different result, the documentation suggests that they should be the
same...

import core.stdc.stdarg, std.stdio;

void main() {
 foo(0,5,4,3);
}

void foo(int dummy, ...) {
 va_list ap;

 for(int i; i10; ++i) {
 version(X86_64) {
 va_start(ap, __va_argsave);
 }
 else version(X86) {
 va_start(ap, dummy);
 }
 else
 static assert(false, Unsupported platform);

 int tmp;
 va_arg!(int)(ap,tmp);
 writeln(ap, , tmp);
 }
}

when compiled with -m32 I get:

FF960278 5
FF960278 5
FF960278 5
FF960278 5
FF960278 5

and with -m64 I get:

7FFFCDF941D0 5
7FFFCDF941D0 4
7FFFCDF941D0 3
7FFFCDF941D0 38
7FFFCDF941D0 -839302560

(the end stuff is garbage, different every time)

I'm uncertain, even after looking over the stdarg src, why this would
happen. The correct output is all 5s obviously.


Known bug, already fixed in git for a couple of months.




Re: Inherited const when you need to mutate

2012-07-11 Thread Don Clugston

On 10/07/12 19:13, H. S. Teoh wrote:

On Tue, Jul 10, 2012 at 06:48:51PM +0200, Timon Gehr wrote:

On 07/10/2012 06:45 PM, H. S. Teoh wrote:

Yeah, this is logical const. Unfortunately, D doesn't have logical
const.



Then why on earth is druntime acting as if it does?


Y'know, this brings up an interesting question. Do methods like toString
_need_ to be const? That is, _physical_ const?  Or are we unconsciously
conflating physical const with logical const here?

Yes, certain runtime operations need to be able to work with const
methods, but I wonder if those required const methods really belong to a
core set of more primitive operations that guarantee physical const, and
perhaps shouldn't be conflated with logical operations like convert
this object to a string representation, which _may_ require caching,
etc.?

Or perhaps application code want to be defining their own non-const
versions of certain methods so that they can do whatever they need to do
with logical const, without worrying about breaking physical const-ness.

I'm starting to think that D's hardline approach to const is clashing
with the principle of information hiding. Users of a class shouldn't
_need_ to know if an object is caching the value of toString, toHash, or
whatever it is. What they care for is that the object doesn't visibly
change, that is, logical const. Binary const implies logical const, but
the implication doesn't work the other way round. While it's nice to
have binary const (strong, enforceable guarantee), it breaks
encapsulation: just because a class needs to do caching, means its
methods can't be const, and this is a visible (and viral, no less)
change in its external API. What should just be an implementation detail
has become a visible difference to the outside world -- encapsulation is
broken.

I don't know how to remedy this. It's clear that physical const does
have its value -- it's necessary to properly support immutable, allows
putting data in ROM, etc.. But it's also clear that something is missing
from the picture. Implementation details are leaking past object APIs,
caching and other abstractions can't work with const, etc., and that's
not a good thing.


T


I think you're right.
Something I wonder about, though, is how many different use cases are we 
dealing with?


Suppose we had a caching solution (you could think of it as @cached, but 
it could be done in a library). The user would need to provide a const, 
pure function which returns the same value that is stored in the cache.
This is enforceable. The only way to write to the cache, is by calling 
the function.


How far would that take us? I don't think there are many use cases for 
logically pure, apart from caching, but I have very little idea about 
logical const.







Re: just an idea (!! operator)

2012-07-11 Thread Don Clugston

On 11/07/12 13:47, monarch_dodra wrote:

On Wednesday, 11 July 2012 at 11:18:21 UTC, akaz wrote:

if needed, the operator !! (double exclamation mark) could be defined.


Problem is that operator!! is already used asa  twin operator!. This
is shorthand for is valid as bool:



I wouldn't be surprised if this is happening in D, so I don't think !!
can be taken for anything.


This is about binary x!!y, not unary !!x.





Re: Exquisite code samples

2012-07-10 Thread Don Clugston

On 10/07/12 09:49, renoX wrote:

On Monday, 9 July 2012 at 11:40:37 UTC, Gor Gyolchanyan wrote:
[cut]

You're right. This is a bit advanced code sample, which uses
templates,template constraints, contract programming among syntax
advantages of D.


Hum it show the power of D sure, but IMHO it also show its syntax
deficiencies..

For me this real[d] bezier(size_t d, Number)(Number[d][] p, Number t)
if(d  1  isFloatingPoint!Number) is difficult to read, and a better
syntax would be:
real[d] bezier!(size_t d  d  1, Number 
isFloatingPoint!Number)(Number[d][] p, Number t)

The template parameter would be indicated in a !() (as in a call), and
the template constraints inside the template parameter: this way the
template parameters are clearly indicated and separated from the
function parameter.

renoX


Well it used to work vaguely in that way, but it gets very ugly once you 
leave the simplest cases.  Even that one you've listed is hard for me to 
read.
And the idea that constraints apply to individual parameters is wrong. 
If you have a constraint that depends on two template parameters, where 
do you put it?


int bezier (int A, int B)(int t) if ( A + B == 10 )






Re: Two Scala annotations

2012-07-03 Thread Don Clugston

On 02/07/12 23:20, Walter Bright wrote:

On 7/2/2012 1:04 PM, bearophile wrote:

Walter Bright:


Put final in front of y, and it will compile. Remember, this was
done for D1
that didn't have const.


I see. So in D2 are we going to require that y to be immutable?


No. I don't agree there's a problem. Nor do I care to break existing D1
code (and D2 for that matter) without an awfully good reason, and I
don't see one here.



This behaviour is *not* currently in the spec.
And if you give any other kind of runtime expression, you get an error 
message which suggests it shouldn't work:


void main()
{
  int x;
  int y;
  switch(x)
  {
  case *y: break;
  }
}

bug.d(10): Error: case must be a string or an integral constant, not *y
--

It would be really difficult to define the current behaviour. I don't 
understand it. Let me explain how bizarre it is.


What it does is, run optimize(WANTvar) on the expression. If at the end 
of optimization, it is a VarExp of type integer or class, then it can be 
a run-time value. It must be a VarExp, it cannot be a DotVar.


Now, what does optimize(WANTvar) actually do? Under what circumstances 
can it produce a VarExp? I'm not sure. You really need to check every 
code path in optimize.c and constfold.c.

It can happen with comma expressions, for example.

So this:
case 7+8, y:
is accepted.

Are there circumstances where X.Y can be accepted? Maybe some 
combination involving alias this or opDispatch ? I don't know.





Re: Raw binary(to work without OS) in D

2012-07-02 Thread Don Clugston

On 28/06/12 18:37, David Nadlinger wrote:

On Thursday, 28 June 2012 at 15:28:10 UTC, Don Clugston wrote:

There's an oddity, though: the type of X.significand would be
dependent on the type of X […]


I don't think this is a problem at all – for example, the type of T.init
depends on T as well…

David


Good point.


Re: Raw binary(to work without OS) in D

2012-07-02 Thread Don Clugston

On 28/06/12 18:36, Jens Mueller wrote:

Don Clugston wrote:

On 28/06/12 17:00, Jens Mueller wrote:

Andrei Alexandrescu wrote:

On 6/28/12 10:07 AM, Roman D. Boiko wrote:

On Thursday, 28 June 2012 at 14:04:37 UTC, Mehrdad wrote:

I think just exposing them via .sig and .exp might be the way to go?


sig is easy to confuse with sign


.mantissa and .exp


Letting the compiler define these properties is a solution. I thought
Don is looking for something more general. But maybe this isn't needed
here. Don't know. But using mantissa should be discouraged.
I suggest calling them
.significand and .exponent

significand is preferred over mantissa by IEEE FP committee. I think
it's fine to spell them out. There won't be much code using them anyway.

Jens



Yes, adding new properties would be the easiest way from a CTFE
perspective; that way, they are endian-ness independent. It's a bit
niche, but then again adding a special case for this in CTFE is
niche as well. Maybe it would be the best approach.


Sounds good then.


With naming, I'm included to agree, but the funny thing is that we
have X.mant_dig as the number of digits in the significand.


You could add a deprecated alias to X.mant_dig and provide a new name.
We should adopt IEEE's vocabulary where possible.


There's an oddity, though: the type of X.significand would be
dependent on the type of X (and for the non-existent quadruple
float, it would be non-existent ucent type!)


But this is no problem, is it?


Would it include the implicit bit of an 80-bit x87 real (the silly bit)?


Not sure what the silly bit is. You mean the bit that is implicitly
always 1, don't you? mant_dig says 24 for a float. Means it is included
when counting the bits. Then for consistency it should be included.


Yes, the implicit bit. For float and double it isn't present, but it's 
there for 80bit x87 and 68K reals.
But it would not be present for quadruple types. I'm not sure if it's 
always present on Itanium 80-bit reals.


It's included in the 80-bit reals only for historical reasons -- it 
seemed like a good idea at the time. It allowed an optimisation for a 
long-obsolete algorithm.


Re: Two Scala annotations

2012-07-02 Thread Don Clugston

On 01/07/12 04:00, Walter Bright wrote:

On 6/30/2012 6:05 PM, bearophile wrote:

Walter Bright:


It's not a bug. It's deliberate, and is there to support mechanical
translation of Java code.


Is this stuff written somewhere in a D design rationales page?

Now that D is several years old, how much Java code was ported to D?
(Despite
there is no mechanical Java-D translator yet).


Yes, a mechanical translator was used extensively to create dwt.


Was this automatic translation
desire worth the troubles (like inner classes,


Yes.


like the risk of killing switch optimizations by mistake)?


Calling it a risk and killing is way, way overstating things.



This post is about two Scala annotations. If that's not a bug, is
something like
that first Scala annotation useful in D too?


I don't really see any problem requiring a solution. If you're working
on optimizations at that level, you ought to be comfortable examining
the asm output for that and all the other stuff, too. Setting a store on
just one aspect of switch implementations is a large mistake.



The problem isn't the effect on optimization. The problem is that the 
semantics are insane. They are like nothing else in the language, and 
they don't make any sense. It's a very complicated feature: eg what 
happens if the case is a shared variable? Under what circumstances is a 
symbol treated as a variable, rather than a constant?


As far as I know, no other language works anything like this. Either 
switch accepts only constants, or it accepts arbitrary expressions. Not 
this bizarre combination of both.


Do you have a reference for this Java behaviour? I did a quick google, 
and everything I found indicates that case labels must be constants.




Re: New hash API: namespace

2012-06-29 Thread Don Clugston

On 25/06/12 20:04, Jesse Phillips wrote:

On Monday, 25 June 2012 at 16:09:43 UTC, Felix Hufnagel wrote:

+1 for
hashes into std.hash
and cryptographic primitives into std.crypto

and we should have a std.net (std.uri, std.socket, std.socketstream ,
std.net.curl, ...),
std.io. for (Outbuffer, file, )
and probably std.database or something like that for (csv, json, xml,
...)


I'd be for not being so flat.


I reckon, follow biology.
There's kingdom.phyllus.class.order.family.genus.species
But in practice, that's far too clumsy. Instead, everyone just uses 
genus.species. And this works even though there are more than a million 
species.


So I reckon two levels of modules is enough. More than that is clumsy.
And, if you're not sure where something should be, because there are two 
or more equally valid alternatives, it should probably be a level closer 
to the root of the tree.




Re: LLVM IR influence on compiler debugging

2012-06-29 Thread Don Clugston

On 29/06/12 08:04, bearophile wrote:

This is a very easy to read article about the design of LLVM:
http://www.drdobbs.com/architecture-and-design/the-design-of-llvm/240001128

That IR has a great effect on making it simpler to debug the compiler, I
think this is important (and I think it partially explains why Clang was
created so quickly):


It's a good design, especially for optimisation tests. Although I can't 
see an immediate application of this for D. DMD's backend is nearly 
bug-free. (By which I mean, it has 100X fewer bugs than the front-end).


Re: Raw binary(to work without OS) in D

2012-06-28 Thread Don Clugston

On 28/06/12 15:31, Jens Mueller wrote:

Andrei Alexandrescu wrote:

On 6/22/12 7:41 AM, Don Clugston wrote:

I think the main thing that's still done in C is the floating point
formatting.


Would be great if a contributor could translate FP parsing and
formatting code into D. Then we can use it in CTFE. I need it badly
for some function tabulation code.


I think formatting cannot be done such that it is CTFE-able. I tried
implementing a less-inefficient version. As far as I can tell at some
point you need to extract the significand and the exponent. This is done
by some unsafe cast which is not allowed in CTFE. I don't know a way
to do it in CTFE-compatible way.

Jens


Yeah, I think I will have to find a way of allowing it. But it's 
difficult to see a clean way of doing it.


Re: Raw binary(to work without OS) in D

2012-06-28 Thread Don Clugston

On 28/06/12 17:00, Jens Mueller wrote:

Andrei Alexandrescu wrote:

On 6/28/12 10:07 AM, Roman D. Boiko wrote:

On Thursday, 28 June 2012 at 14:04:37 UTC, Mehrdad wrote:

I think just exposing them via .sig and .exp might be the way to go?


sig is easy to confuse with sign


.mantissa and .exp


Letting the compiler define these properties is a solution. I thought
Don is looking for something more general. But maybe this isn't needed
here. Don't know. But using mantissa should be discouraged.
I suggest calling them
.significand and .exponent

significand is preferred over mantissa by IEEE FP committee. I think
it's fine to spell them out. There won't be much code using them anyway.

Jens



Yes, adding new properties would be the easiest way from a CTFE 
perspective; that way, they are endian-ness independent. It's a bit 
niche, but then again adding a special case for this in CTFE is niche as 
well. Maybe it would be the best approach.


With naming, I'm included to agree, but the funny thing is that we have 
X.mant_dig as the number of digits in the significand.


There's an oddity, though: the type of X.significand would be dependent 
on the type of X (and for the non-existent quadruple float, it would be 
non-existent ucent type!)

Would it include the implicit bit of an 80-bit x87 real (the silly bit)?



Re: A little story

2012-06-26 Thread Don Clugston

On 25/06/12 14:24, bearophile wrote:

Dmitry Olshansky:


Except for the fact, that someone has to implement it.


I am not seeing one of the posts of this thread. So I'll answer here.

The good thing regarding the run-time overflow integral tests is that
they are already implemented and available as efficient compiler
intrinsics in both GCC and LLVM back-ends. It's just a matter of using
them (and introducing the compiler switch and some kind of pragma syntax).

Bye,
bearophile


Bearophile, haven't you ever read that paper on integer overflow, which 
you keep posting to the newsgroup???


It clearly demonstrates that it is NOT POSSIBLE to implement integer 
overflow checking in a C-family language. Valid, correct, code which 
depends on integer overflow is very, very common (when overflow occurs, 
it's more likely to be correct, than incorrect).


I don't think you could do it without introducing a no-overflow integer 
type. The compiler just doesn't have enough information.




Re: Raw binary(to work without OS) in D

2012-06-22 Thread Don Clugston

On 22/06/12 10:08, Mehrdad wrote:

On Friday, 22 June 2012 at 08:00:08 UTC, Dmitry Olshansky wrote:

Then implement the ones you happen to actually need.



Er, the question isn't WHAT to do, it's HOW.

If you have any idea how to implement things like TLS, SEH, and the
like, then PLEASE, share them!


On Windows, all of the SEH code is in D. The C library isn't used any more.

I think the main thing that's still done in C is the floating point 
formatting.



The point I was trying to make was, though, that this information is not
being shared with anyone.

Which leads me to believe that whoever has this information doesn't want
people to use it for D development...




Re: GDC review process.

2012-06-21 Thread Don Clugston

On 20/06/12 16:37, Manu wrote:

On 20 June 2012 17:15, Don Clugston d...@nospam.com
mailto:d...@nospam.com wrote:

On 20/06/12 13:22, Manu wrote:

I find optimisers are very good at code simplification, assuming
that

you massage the code/expressions to neatly match any
architectural quirks.
I also appreciate that good x86 code is possibly the hardest
architecture for an optimiser to get right...


Optimizers improved enormously during the 80's and 90's, but the
rate of improvement seems to have slowed.

With x86, out-of-order execution has made it very easy to get
reasonably good code, and much harder to achieve perfection. Still,
Core i7 is much easier than Core2, since Intel removed one of the
most complicated bottlenecks (on core2 and earlier there is a max 3
reads per cycle, of registers you haven't written to in the previous
3 cycles).


Yeah okay, I can easily imagine the complexity for an x86 codegen.
RISC architectures are so much more predictable.

How do you define 'perfection'? Performance as measured on what
particular machine? :)


The theoretical limit for a particular architecture. Eg in BigInt, the 
most crucial functions an integer multiply in each loop iteration.
Since the machine only has one integer multiply unit, it is impossible 
to do better than one multiply per cycle. If you've achieved that, it's 
perfect.
If the processors are different enough you may also need a separate 
branch for different processors.


Re: How to break const

2012-06-20 Thread Don Clugston

On 19/06/12 11:02, Iain Buclaw wrote:

On 19 June 2012 09:18, Don Clugstond...@nospam.com  wrote:

So would I. Can you think of one?
It was the best name I could come up with, given that the 'pure' was the
keyword.
We want a word that means 'no hidden state'.


I thought that was what pure was for. :~)


This page is interesting.

http://en.wikipedia.org/wiki/Pure_function

There's never any hidden state, even in a weakly pure function.
So it satisfies rule 1.
A weakly pure function may modify anything it can reach through the 
parameters, though. Does this violate rule 2?


I guess that if you define all mutable arguments of a weakly pure 
function as being 'pass by reference', then even 'weakly pure' is pure 
according to that definition.


The page states that according to that definition, the expressions which 
call the pure function are not pure.
But again in the terms of that page, D has an Effect System which 
allow us to prove that a function is pure even though it has impure 
expressions in it.


Wikipedia isn't very authoritative though.

So I don't know -- although D 'pure' is very different to what FP people 
call 'pure', I'm no longer certain that we're abusing the term.


After all, even this function isn't pure in the traditional FP view:

int foo(int n) pure
{
   int r = n*n;
   r += n;
   return r;
}


Re: GDC review process.

2012-06-20 Thread Don Clugston

On 19/06/12 20:19, Iain Buclaw wrote:

Hi,

Had round one of the code review process, so I'm going to post the main
issues here that most affect D users / the platforms they want to run on
/ the compiler version they want to use.



1) D Inline Asm and naked function support is raising far too many alarm
bells. So would just be easier to remove it and avoid all the other
comments on why we need middle-end and backend headers in gdc.


You seem to be conflating a couple of unrelated issues here.
One is the calling convention. The other is inline asm.

Comments in the thread about asm is mostly used for short things which 
get inlined leave me completely baffled, as it is completely wrong.


There are two uses for asm, and they are very different:
(1) Functionality. This happens when there are gaps in the language, and 
you get an abstraction inversion. You can address these with intrinsics.

(2) Speed. High-speed, all-asm functions. These _always_ include a loop.


You seem to be focusing on (1), but case (2) is completely different.

Case (2) cannot be replaced with intrinsics. For example, you can't 
write asm code using MSVC intrinsics (because the compiler rewrites your 
code).
Currently, D is the best way to write (2). It is much, much better than 
an external assembler.


Re: GDC review process.

2012-06-20 Thread Don Clugston

On 20/06/12 03:01, Alex Rønne Petersen wrote:

On 20-06-2012 02:58, Timon Gehr wrote:

On 06/20/2012 02:04 AM, Alex Rønne Petersen wrote:

On 20-06-2012 01:55, Timon Gehr wrote:

On 06/20/2012 12:47 AM, Alex Rønne Petersen wrote:

On 19-06-2012 23:52, Walter Bright wrote:

On 6/19/2012 1:36 PM, bearophile wrote:

No, but the idea was to allow D to innovate on calling
conventions without disturbing code that needed to
interface with C.


The idea is nice, but ideas aren't enough. Where are the benchmarks
that show a
performance improvement over the C calling convention? And even if
such
improvement is present, is it worth it in the face of people that
don't want to
add it to GCC?


GDC can certainly define its D calling convention to match GCC's.
It's
an implementation defined thing, not a language defined one.



Then let's please rename it to the DMD ABI instead of calling it the D
ABI and making it look like it's part of the language on the website.
Further, D mangling rules should be separate from calling convention.



IIRC currently, the calling convention is mangled into the symbol name.
Do you want to remove this?


Not that I can see from http://dlang.org/abi.html ?



TypeFunction:
CallConvention FuncAttrs Arguments ArgClose Type

CallConvention:
F // D
U // C
W // Windows
V // Pascal
R // C++



I see. I think it's a mistake to call that calling convention D. I'm
not against removing it, but the description is highly misleading.


And C++ calling convention doesn't make any sense. There is no such 
thing. On Windows, every vendor does it differently (even the ones who 
claim to be compatible with one another!).


Re: GDC review process.

2012-06-20 Thread Don Clugston

On 20/06/12 00:55, Manu wrote:

On 20 June 2012 01:07, Walter Bright newshou...@digitalmars.com
mailto:newshou...@digitalmars.com wrote:

On 6/19/2012 1:58 PM, Manu wrote:

I find a thorough suite of architecture intrinsics are usually
the fastest and
cleanest way to the best possible code, although 'naked' may be
handy in this
circumstance too...


Do a grep for naked across the druntime library sources. For
example, its use in druntime/src/rt/alloca.d, where it is very much
needed, as alloca() is one of those magic functions.


I never argued against naked... I agree it's mandatory.


Do a grep for asm across the druntime library sources. Can you
justify all of that with some other scheme?


I think almost all the blocks I just browsed through could be easily
written with nothing more than the register alias feature I suggested,
and perhaps a couple of opcode intrinsics.
And as a bonus, they would also be readable. I can imagine cases where
the optimiser would have more freedom too.


Thinking more about the implications of removing the inline asm,
what would
REALLY roxors, would be a keyword to insist a variable is
represented by a
register, and by extension, to associate it with a specific
register:


This was a failure in C.


Really? This is the missing link between mandatory asm blocks, and being
able to do it in high level code with intrinsics.
The 'register' keyword was similarly fail as 'inline'.. __forceinline
was not fail, it is actually mandatory. I'd argue that __forceregister
would be similarly useful in C aswell, but the real power would come
from being able to specify the particular register to alias.

This would almost entirely eliminate the usefulness of an inline
assembler.
Better yet, this could use the 'new' attribute syntax, which
most agree will
support arguments:
@register(rsp) int x;


Some C compilers did have such pseudo-register abilities. It was a
failure in practice.


Really? I've never seen that. What about it was fail?

I really don't understand preferring all these rather convoluted
enhancements to avoid something simple and straightforward like the
inline assembler. The use of IA in the D runtime library, for
example, has been quite successful.


I agree, IA is useful and has been successful, but it has drawbacks too.
   * IA ruins optimisation around the IA block
   * IA doesn't inline well. intrinsics allow much greater opportunity
for efficient integration into the calling context
   * most IA functions are small, and prime candidates for inlining (see
points 1 and 2)


You and I seem to be from different planets. I have almost never written 
as asm function which was suitable for inlining.


Take a look at std.internal.math.biguintX86.d

I do not know how to write that code without inline asm.


Re: GDC review process.

2012-06-20 Thread Don Clugston

On 20/06/12 13:04, Manu wrote:

On 20 June 2012 13:51, Don Clugston d...@nospam.com
mailto:d...@nospam.com wrote:

On 19/06/12 20:19, Iain Buclaw wrote:

Hi,

Had round one of the code review process, so I'm going to post
the main
issues here that most affect D users / the platforms they want
to run on
/ the compiler version they want to use.



1) D Inline Asm and naked function support is raising far too
many alarm
bells. So would just be easier to remove it and avoid all the other
comments on why we need middle-end and backend headers in gdc.


You seem to be conflating a couple of unrelated issues here.
One is the calling convention. The other is inline asm.

Comments in the thread about asm is mostly used for short things
which get inlined leave me completely baffled, as it is completely
wrong.

There are two uses for asm, and they are very different:
(1) Functionality. This happens when there are gaps in the language,
and you get an abstraction inversion. You can address these with
intrinsics.
(2) Speed. High-speed, all-asm functions. These _always_ include a loop.


You seem to be focusing on (1), but case (2) is completely different.

Case (2) cannot be replaced with intrinsics. For example, you can't
write asm code using MSVC intrinsics (because the compiler rewrites
your code).
Currently, D is the best way to write (2). It is much, much better
than an external assembler.


Case 1 has no alternative to inline asm. I've thrown out some crazy
ideas to think about (but nobody seems to like them). I still think it
could be addressed though.

Case 2; I'm not convinced. These such long functions are the type I'm
generally interested in aswell, and have the most experience with. But
in my experience, they're almost always best written with intrinsics.
If they're small enough to be inlined, then you can't afford not to use
intrinsics. If they are truly big functions, then you begin to sacrifice
readability and maintain-ability, and certainly limit the number of
programmers that can maintain the code.


I don't agree with that. In the situations I'm used to, using intrinsics 
would not make it easier to read, and would definitely not make it 
easier to maintain. I find it inconceivable that somebody could 
understand the processor well enough to maintain the code, and yet not 
understand asm.



I rarely fail to produce identical code with intrinsics to that which I
would write with hand written asm. The flags are always the biggest
challenge, as discussed prior in this thread. I think that could be
addressed with better intrinsics.


Again, look at std.internal.math.BiguintX86. There are many cases there 
where you can swap two instructions, and the code will still produce the 
correct result, but it will be 30% slower.


I think that the SIMD case gives you a misleading impression, because on 
x86 they are very easy to schedule (they nearly all take the same number 
of cycles, etc). So it's not hard for the compiler to do a good job of it.


Re: GDC review process.

2012-06-20 Thread Don Clugston

On 20/06/12 13:22, Manu wrote:

On 20 June 2012 13:59, Don Clugston d...@nospam.com
mailto:d...@nospam.com wrote:

You and I seem to be from different planets. I have almost never
written as asm function which was suitable for inlining.

Take a look at std.internal.math.biguintX86.d

I do not know how to write that code without inline asm.


Interesting.
I wish I could paste some counter-examples, but they're all proprietary _

I think they key detail here is where you stated, they _always_ include
a loop. Is this because it's hard to manipulate the compiler into the
correct interaction with the flags register?


No. It's just because speed doesn't matter outside loops. A consequence 
of having the loop be inside the asm code, is that the parameter passing 
is much less significant for speed, and calling convention is the big



I'd be interested to compare the compiled D code, and your hand written
asm code, to see where exactly the optimiser goes wrong. It doesn't look
like you're exploiting too many tricks (at a brief glance), it's just
nice tight hand written code, which the optimiser should theoretically
be able to get right...


Theoretically, yes. In practice, DMD doesn't get anywhere near, and gcc 
isn't much better. I don't think there's any reason why they couldn't, 
but I don't have much hope that they will.


As you say, the code looks fairly straightforward, but actually there 
are very many similar ways of writing the code, most of which are much 
slower. There are many bottlenecks you need to avoid. I was only able to 
get it to that speed by using the processor profiling registers.


So, my original two uses for asm are actually:
(1) when the language prevents you from accessing low-level 
functionality; and

(2) when the optimizer isn't good enough.


I find optimisers are very good at code simplification, assuming that
you massage the code/expressions to neatly match any architectural quirks.
I also appreciate that good x86 code is possibly the hardest
architecture for an optimiser to get right...


Optimizers improved enormously during the 80's and 90's, but the rate of 
improvement seems to have slowed.


With x86, out-of-order execution has made it very easy to get reasonably 
good code, and much harder to achieve perfection. Still, Core i7 is much 
easier than Core2, since Intel removed one of the most complicated 
bottlenecks (on core2 and earlier there is a max 3 reads per cycle, of 
registers you haven't written to in the previous 3 cycles).


Re: GDC review process.

2012-06-20 Thread Don Clugston

On 20/06/12 14:51, Manu wrote:

On 20 June 2012 14:44, Don Clugston d...@nospam.com
mailto:d...@nospam.com wrote:

On 20/06/12 13:04, Manu wrote:

On 20 June 2012 13:51, Don Clugston d...@nospam.com
mailto:d...@nospam.com

mailto:d...@nospam.com mailto:d...@nospam.com wrote:

On 19/06/12 20:19, Iain Buclaw wrote:

Hi,

Had round one of the code review process, so I'm going
to post
the main
issues here that most affect D users / the platforms
they want
to run on
/ the compiler version they want to use.



1) D Inline Asm and naked function support is raising
far too
many alarm
bells. So would just be easier to remove it and avoid
all the other
comments on why we need middle-end and backend headers
in gdc.


You seem to be conflating a couple of unrelated issues here.
One is the calling convention. The other is inline asm.

Comments in the thread about asm is mostly used for short
things
which get inlined leave me completely baffled, as it is
completely
wrong.

There are two uses for asm, and they are very different:
(1) Functionality. This happens when there are gaps in the
language,
and you get an abstraction inversion. You can address these with
intrinsics.
(2) Speed. High-speed, all-asm functions. These _always_
include a loop.


You seem to be focusing on (1), but case (2) is completely
different.

Case (2) cannot be replaced with intrinsics. For example,
you can't
write asm code using MSVC intrinsics (because the compiler
rewrites
your code).
Currently, D is the best way to write (2). It is much, much
better
than an external assembler.


Case 1 has no alternative to inline asm. I've thrown out some crazy
ideas to think about (but nobody seems to like them). I still
think it
could be addressed though.

Case 2; I'm not convinced. These such long functions are the
type I'm
generally interested in aswell, and have the most experience
with. But
in my experience, they're almost always best written with
intrinsics.
If they're small enough to be inlined, then you can't afford not
to use
intrinsics. If they are truly big functions, then you begin to
sacrifice
readability and maintain-ability, and certainly limit the number of
programmers that can maintain the code.


I don't agree with that. In the situations I'm used to, using
intrinsics would not make it easier to read, and would definitely
not make it easier to maintain. I find it inconceivable that
somebody could understand the processor well enough to maintain the
code, and yet not understand asm.


These functions of yours are 100% asm, that's not really what I would
usually call 'inline asm'. That's really just 'asm' :)
I think you've just illustrated one of my key points actually; that is
that you can't just insert small inline asm blocks within regular code,
the optimiser can't deal with it in most cases, so inevitably, the
entire function becomes asm from start to end.


Personally I call it inline asm if I don't need to use a separate 
assembler. If you're using a different definition, then we don't 
actually disagree.




I find I can typically produce equivalent code using carefully crafted
intrinsics within regular C language structures. Also, often enough, the
code outside the hot loop can be written in normal C for readability,
since it barely affects performance, and trivial setup code will usually
optimise perfectly anyway.

You're correct that a person 'maintaining' such code, who doesn't have
such a thorough understanding of the codegen may ruin it's perfectly
tuned efficiency. This may be the case, but in a commercial coding
environment, where a build MUST be delivered yesterday, the guy that
understands it is on holiday, and you need to tweak the behaviour
immediately, this is a much safer position to be in.
This is a very real scenario. I can't afford to ignore this practical
reality.


OK, it sounds like your use case is a bit different. The kinds of things 
I deal with are



I might have a go at compiling the regular D code tonight, and seeing if
I can produce identical assembly. I haven't tried this so much with x86
as I have with RISC architectures, which have much more predictable codegen.


I rarely fail to produce identical code with intrinsics to that
which I
would write with hand written asm. The flags are always the biggest
challenge, as discussed prior

Re: How to break const

2012-06-19 Thread Don Clugston

On 18/06/12 17:00, Artur Skawina wrote:

On 06/18/12 16:41, deadalnix wrote:

Le 18/06/2012 16:28, Artur Skawina a écrit :

It's fine, if you view a delegate as opaque.



No it isn't. You cannot ensure transitivity anywhere. This have obvious, and 
severe drawback for concurrent programing (implicit sharing is back) and GC 
performances (GC can eb crazy fast when it come to transitive immutable data, 
see OCaml's GC performances for instance).


'this' being const does not preclude accessing the object that 'this'
points to via another, mutable, reference.

Consider the alternative - you'd have to forbid storing any delegate
with a non-const non-value argument inside any object.


So how would you like to handle this? And, no, allowing only the cases
that /can/ be statically checked is not ok - it would result in black
magic - delegates would be accepted or not depending on the contents
of the object (think templates and composition).


And breaking const would then _still_ be possible and trivial.



No, and your example don't demonstrate that in any way. Transitivity is 
maintained in the example below, because g isn't a member of s, and if it were, 
then the example would break at compile time.


The word breaking is in quotes for a reason. Const is not an immutability
guarantee. If you treat delegates as opaque then there's no practical
difference between using them or accessing the data via another external
reference.


purity is another beast altogether.


D's weak pure can help; I just don't like the redefinition of the term
purity; another name for weak purity would be better.


So would I. Can you think of one?
It was the best name I could come up with, given that the 'pure' was the 
keyword.

We want a word that means 'no hidden state'.


Re: AST files instead of DI interface files for faster compilation and easier distribution

2012-06-18 Thread Don Clugston

On 17/06/12 00:37, Walter Bright wrote:

On 6/14/2012 1:03 AM, Don Clugston wrote:

It is for debug builds.

Iain's data indicates that it's only a few % of the time taken on
semantic1().
Do you have data that shows otherwise?


Nothing recent, it's mostly from my C++ compiler testing.


But you argued in your blog that C++ parsing is inherently slow, and 
you've fixed those problems in the design of D.

And as far as I can tell, you were extremely successful!
Parsing in D is very, very fast.


Yes, it is designed so you could just import a symbol table. It is done
as source code, however, because it's trivial to implement.


It has those nasty side-effects listed under (3) though.


I don't think they're nasty or are side effects.


They are new problems which people ask for solutions for. And they are 
far more difficult to solve than the original problem.


Re: AST files instead of DI interface files for faster compilation and easier distribution

2012-06-15 Thread Don Clugston

On 14/06/12 10:10, Jonathan M Davis wrote:

On Thursday, June 14, 2012 10:03:05 Don Clugston wrote:

On 13/06/12 16:29, Walter Bright wrote:

On 6/13/2012 1:07 AM, Don Clugston wrote:

On 12/06/12 18:46, Walter Bright wrote:

On 6/12/2012 2:07 AM, timotheecour wrote:

There's a current pull request to improve di file generation
(https://github.com/D-Programming-Language/dmd/pull/945); I'd like to
suggest
further ideas.
As far as I understand, di interface files try to achieve these
conflicting goals:

1) speed up compilation by avoiding having to reparse large files over
and over.
2) hide implementation details for proprietary reasons
3) still maintain source code in some form to allow inlining and CTFE
4) be human readable


(4) was not a goal.

A .di file could very well be a binary file, but making it look like D
source enabled them to be loaded with no additional implementation work
in the compiler.


I don't understand (1) actually.

For two reasons:
(a) Is lexing + parsing really a significant part of the compilation
time? Has
anyone done some solid profiling?


It is for debug builds.


Iain's data indicates that it's only a few % of the time taken on
semantic1().
Do you have data that shows otherwise?

It seems to me, that slow parsing is a C++ problem which D already solved.


If this is the case, is there any value at all to using .di files in druntime
or Phobos other than in cases where we're specifically trying to hide
implementation (e.g. with the GC)? Or do we still end up paying the semantic
cost for importing the .d files such that using .di files would still help with
compilation times?

- Jonathan M Davis


I don't think Phobos should use .di files at all. I don't think there 
are any cases where we want to conceal code.


The performance benefit you would get is completely negligible. It 
doesn't even reduce the number of files that need to be loaded, just the 
length of each one.


I think that, for example, improving the way that array literals are 
dealt with would have at least as much impact on compilation time.
For the DMD backend, fixing up the treatment of comma expressions would 
have a much bigger impact than getting lexing and parsing time to zero.


And we're well set up for parallel compilation. There's no shortage of 
things we can do to improve compilation time.


Using di files for speed seems a bit like jettisoning the cargo to keep 
the ship afloat. It works but you only do it when you've got no other 
options.


Re: static array literal syntax request: auto x=[1,2,3]S;

2012-06-15 Thread Don Clugston

On 10/06/12 23:43, Jonathan M Davis wrote:

On Sunday, June 10, 2012 23:23:57 Mehrdad wrote:

I honestly don't see the POINT of having a dynamic array
literal.

What's the point of making the literals dynamic?

They should all be static, and only converted to dynamic if
necessary from the context.

But I really don't see the benefit of allocating them on the heap
just because we can... perhaps someone can enlighten me?


In the vast majority of cases where an array literal is used, it's assigned to
a dynamic array.


I doubt that very much. I know it's not true in my code, I use array 
literals almost exclusively for immutable values.
Usually if you are initializing an array, where you will modify the 
elements later, you want all values to be the same.


I argued that array literals should be immutable, just as string 
literals are. But I lost.


Re: AST files instead of DI interface files for faster compilation and easier distribution

2012-06-14 Thread Don Clugston

On 13/06/12 16:29, Walter Bright wrote:

On 6/13/2012 1:07 AM, Don Clugston wrote:

On 12/06/12 18:46, Walter Bright wrote:

On 6/12/2012 2:07 AM, timotheecour wrote:

There's a current pull request to improve di file generation
(https://github.com/D-Programming-Language/dmd/pull/945); I'd like to
suggest
further ideas.
As far as I understand, di interface files try to achieve these
conflicting goals:

1) speed up compilation by avoiding having to reparse large files over
and over.
2) hide implementation details for proprietary reasons
3) still maintain source code in some form to allow inlining and CTFE
4) be human readable


(4) was not a goal.

A .di file could very well be a binary file, but making it look like D
source enabled them to be loaded with no additional implementation work
in the compiler.


I don't understand (1) actually.

For two reasons:
(a) Is lexing + parsing really a significant part of the compilation
time? Has
anyone done some solid profiling?


It is for debug builds.


Iain's data indicates that it's only a few % of the time taken on 
semantic1().

Do you have data that shows otherwise?

It seems to me, that slow parsing is a C++ problem which D already solved.




(b) Wasn't one of the goals of D's module system supposed to be that
you could
import a symbol table? Why not just implement that? Seems like that
would be
much faster than .di files can ever be.


Yes, it is designed so you could just import a symbol table. It is done
as source code, however, because it's trivial to implement.


It has those nasty side-effects listed under (3) though.


Re: AST files instead of DI interface files for faster compilation and easier distribution

2012-06-13 Thread Don Clugston

On 12/06/12 18:46, Walter Bright wrote:

On 6/12/2012 2:07 AM, timotheecour wrote:

There's a current pull request to improve di file generation
(https://github.com/D-Programming-Language/dmd/pull/945); I'd like to
suggest
further ideas.
As far as I understand, di interface files try to achieve these
conflicting goals:

1) speed up compilation by avoiding having to reparse large files over
and over.
2) hide implementation details for proprietary reasons
3) still maintain source code in some form to allow inlining and CTFE
4) be human readable


(4) was not a goal.

A .di file could very well be a binary file, but making it look like D
source enabled them to be loaded with no additional implementation work
in the compiler.


I don't understand (1) actually.

For two reasons:
(a) Is lexing + parsing really a significant part of the compilation 
time? Has anyone done some solid profiling?


(b) Wasn't one of the goals of D's module system supposed to be that you 
could import a symbol table? Why not just implement that? Seems like 
that would be much faster than .di files can ever be.


Re: AST files instead of DI interface files for faster compilation and easier distribution

2012-06-12 Thread Don Clugston

On 12/06/12 11:07, timotheecour wrote:

There's a current pull request to improve di file generation
(https://github.com/D-Programming-Language/dmd/pull/945); I'd like to
suggest further ideas.
As far as I understand, di interface files try to achieve these
conflicting goals:

1) speed up compilation by avoiding having to reparse large files over
and over.
2) hide implementation details for proprietary reasons

 3) still maintain source code in some form to allow inlining and CTFE
 4) be human readable

Is that actually true? My recollection is that the original motivation 
was only goal (2), but I was fairly new to D at the time (2005).


Here's the original post where it was implemented:
http://www.digitalmars.com/d/archives/digitalmars/D/29883.html
and it got partially merged into DMD 0.141 (Dec 4 2005), first usable in 
DMD0.142


Personally I believe that.di files are *totally* the wrong approach for 
goal (1). I don't think goal (1) and (2) have anything in common at all 
with each other, except that C tried to achieve both of them using 
header files. It's an OK solution for (1) in C, it's a failure in C++, 
and a complete failure in D.


IMHO: If we want goal (1), we should try to achieve goal (1), and stop 
pretending its in any way related to goal (2).


Re: runtime hook for Crash on Error

2012-06-06 Thread Don Clugston

On 05/06/12 17:44, Jonathan M Davis wrote:

On Tuesday, June 05, 2012 13:57:14 Don Clugston wrote:

On 05/06/12 09:07, Jonathan M Davis wrote:

On Tuesday, June 05, 2012 08:53:16 Don Clugston wrote:

On 04/06/12 21:29, Steven Schveighoffer wrote:

On Mon, 04 Jun 2012 06:20:56 -0400, Don Clugstond...@nospam.com   wrote:

1. There exist cases where you cannot know why the assert failed.
2. Therefore you never know why an assert failed.
3. Therefore it is not safe to unwind the stack from a nothrow
function.

Spot the fallacies.

The fallacy in moving from 2 to 3 is more serious than the one from 1
to 2: this argument is not in any way dependent on the assert occuring
in a nothrow function. Rather, it's an argument for not having
AssertError at all.


I'm not sure that is the issue here at all. What I see is that the
unwinding of the stack is optional, based on the assumption that there's
no right answer.

However, there is an underlying driver for not unwinding the stack --
nothrow. If nothrow results in the compiler optimizing out whatever
hooks a function needs to properly unwind itself (my limited
understanding is that this helps performance), then there *is no
choice*, you can't properly unwind the stack.

-Steve


No, this whole issue started because the compiler currently does do
unwinding whenever it can. And Walter claimed that's a bug, and it
should be explicitly disabled.

It is, in my view, an absurd position. AFAIK not a single argument has
been presented in favour of it. All arguments have been about you
should never unwind Errors.


It's quite clear that we cannot completely, correctly unwind the stack in
the face of Errors.


Well that's a motherhood statement. Obviously in the face of extreme
memory corruption you can't guarantee *any* code is valid.
The *main* reason why stack unwinding would not be possible is if
nothrow intentionally omits stack unwinding code.


It's not possible precisely because of nothrow.



nothrow only means 'does not throw Exceptions'. It doesn't mean 'does 
not throw Errors'.

Therefore, given:

int foo() nothrow { ...}


try
{
   foo();
} catch (Error e)
{
  ...
}

even though there are no throw statements inside foo(), the compiler is 
NOT permitted to remove the catch(Error), whereas it could remove 
catch(Exception).


The problem is 'finally' clauses. Are they called only on Exception, or 
on Exception and Error?



Regardless, I think that there are a number of people in this thread who
are mistaken in how recoverable they think Errors and/or segfaults are,
and they seem to be the ones pushing the hardest for full stack unwinding
on the theory that they could somehow ensure safe recovery and a clean
shutdown when an Error occurs, which is almost never possible, and
certainly isn't possible in the general case.

- Jonathan M Davis


Well I'm pushing it because I implemented it (on Windows).

I'm less knowledgeable about what happens on other systems, but know
that on Windows, the whole system is far, far more robust than most
people on this thread seem to think.

I can't see *any* problem with executing catch(Error) clauses. I cannot
envisage a situation where that can cause a problem. I really cannot.


In many cases, it's probably fine, but if the program is in a bad enough state
that an Error is thrown, then you can't know for sure that any particular such
block will execute properly (memory corruption being the extreme case), and if
it doesn't run correctly, then it could make things worse (e.g. writing
invalid data to a file, corrupting that file). Also, if the stack is not unwound
perfectly (as nothrow prevents), then the program's state will become
increasingly invalid the farther that the program gets from the throw point,
which will increase the chances of cleanup code functioning incorrectly, as
any assumptions that they've made about the program state are increasingly
likely to be wrong (as well as it being increasingly likely that the variables
that they operate on no longer being valid).

A lot of it comes down to worst case vs typical case. In the typical case, the
code causing the Error is isolated enough and the code doing the cleanup is
self-contained enough that trying to unwind the stack as much as possible will
result in more correct behavior than skipping it all. But in the worst case,
you can't rely on running any code being safe, because the state of the
program is very much invalid, in which case, it's better to kill the program
ASAP. Walter seems to subscribe to the approach that it's best to assume the
worst case (e.g. that an assertion failure indicates horrible memory
corruption), and always have Errors function that way, whereas others
subscribe to the approach that things are almost never that bad, so we should
just assume that they aren't, since skipping all of that cleanup causes other
problems.


I believe I now understand the root issue behind this dispute.

Consider:

if (x) throw new FileError;

if (x) throw new

Re: runtime hook for Crash on Error

2012-06-05 Thread Don Clugston

On 04/06/12 21:29, Steven Schveighoffer wrote:

On Mon, 04 Jun 2012 06:20:56 -0400, Don Clugston d...@nospam.com wrote:


1. There exist cases where you cannot know why the assert failed.
2. Therefore you never know why an assert failed.
3. Therefore it is not safe to unwind the stack from a nothrow function.

Spot the fallacies.

The fallacy in moving from 2 to 3 is more serious than the one from 1
to 2: this argument is not in any way dependent on the assert occuring
in a nothrow function. Rather, it's an argument for not having
AssertError at all.


I'm not sure that is the issue here at all. What I see is that the
unwinding of the stack is optional, based on the assumption that there's
no right answer.

However, there is an underlying driver for not unwinding the stack --
nothrow. If nothrow results in the compiler optimizing out whatever
hooks a function needs to properly unwind itself (my limited
understanding is that this helps performance), then there *is no
choice*, you can't properly unwind the stack.

-Steve


No, this whole issue started because the compiler currently does do 
unwinding whenever it can. And Walter claimed that's a bug, and it 
should be explicitly disabled.


It is, in my view, an absurd position. AFAIK not a single argument has 
been presented in favour of it. All arguments have been about you 
should never unwind Errors.


Re: AST Macros?

2012-06-05 Thread Don Clugston

On 04/06/12 20:46, Jacob Carlborg wrote:

On 2012-06-04 10:03, Don Clugston wrote:


AST macros were discussed informally on the day after the conference,
and it quickly became clear that the proposed ones were nowhere near
powerful enough. Since that time nobody has come up with another
proposal, as far as I know.


I think others have suggested doing something similar like Nemerle,
Scala or Nimrod.



Yes but only in very vague terms -- not in any more words than that. 
When I look at the Nimrod docs, it basically seems to be nothing more 
than expose the compiler internal data structures. Which is extremely 
easy to do but causes a heap of problems in the long term.





Re: runtime hook for Crash on Error

2012-06-05 Thread Don Clugston

On 05/06/12 09:07, Jonathan M Davis wrote:

On Tuesday, June 05, 2012 08:53:16 Don Clugston wrote:

On 04/06/12 21:29, Steven Schveighoffer wrote:

On Mon, 04 Jun 2012 06:20:56 -0400, Don Clugstond...@nospam.com  wrote:

1. There exist cases where you cannot know why the assert failed.
2. Therefore you never know why an assert failed.
3. Therefore it is not safe to unwind the stack from a nothrow function.

Spot the fallacies.

The fallacy in moving from 2 to 3 is more serious than the one from 1
to 2: this argument is not in any way dependent on the assert occuring
in a nothrow function. Rather, it's an argument for not having
AssertError at all.


I'm not sure that is the issue here at all. What I see is that the
unwinding of the stack is optional, based on the assumption that there's
no right answer.

However, there is an underlying driver for not unwinding the stack --
nothrow. If nothrow results in the compiler optimizing out whatever
hooks a function needs to properly unwind itself (my limited
understanding is that this helps performance), then there *is no
choice*, you can't properly unwind the stack.

-Steve


No, this whole issue started because the compiler currently does do
unwinding whenever it can. And Walter claimed that's a bug, and it
should be explicitly disabled.

It is, in my view, an absurd position. AFAIK not a single argument has
been presented in favour of it. All arguments have been about you
should never unwind Errors.


It's quite clear that we cannot completely, correctly unwind the stack in the
face of Errors.


Well that's a motherhood statement. Obviously in the face of extreme 
memory corruption you can't guarantee *any* code is valid.
The *main* reason why stack unwinding would not be possible is if 
nothrow intentionally omits stack unwinding code.



As such, no one should be relying on stack unwinding when an
Error is thrown.


This conclusion DOES NOT FOLLOW. And I am getting so sick of the number 
of times this fallacy has been repeated in this thread.


These kinds of generalizations are completely invalid in a systems 
programming language.



Regardless, I think that there are a number of people in this thread who are
mistaken in how recoverable they think Errors and/or segfaults are, and they
seem to be the ones pushing the hardest for full stack unwinding on the theory
that they could somehow ensure safe recovery and a clean shutdown when an
Error occurs, which is almost never possible, and certainly isn't possible in
the general case.

- Jonathan M Davis


Well I'm pushing it because I implemented it (on Windows).

I'm less knowledgeable about what happens on other systems, but know 
that on Windows, the whole system is far, far more robust than most 
people on this thread seem to think.


I can't see *any* problem with executing catch(Error) clauses. I cannot 
envisage a situation where that can cause a problem. I really cannot.


And catch(Exception) clauses won't be run, because of the exception 
chaining scheme we have implemented.


The only difficult case is 'finally' clauses, which may be expecting an 
Exception.


Re: floats default to NaN... why?

2012-06-05 Thread Don Clugston

On 14/04/12 16:52, F i L wrote:

On Saturday, 14 April 2012 at 10:38:45 UTC, Silveri wrote:

On Saturday, 14 April 2012 at 07:52:51 UTC, F i L wrote:

On Saturday, 14 April 2012 at 06:43:11 UTC, Manfred Nowak wrote:

F i L wrote:

4) use hardware signalling to overcome some of the limitations
impressed by 3).


4) I have no idea what you just said... :)


On Saturday, 14 April 2012 at 07:58:44 UTC, F i L wrote:

That's interesting, but what effect does appending an invalid char to
a valid one have? Does the resulting string end up being NaS (Not a
String)? Cause if not, I'm not sure that's a fair comparison.


The initialization values chosen are also determined by the underlying
hardware implementation of the type. Signalling NANs
(http://en.wikipedia.org/wiki/NaN#Signaling_NaN) can be used with
floats because they are implemented by the CPU, but in the case of
integers or strings their aren't really equivalent values.


I'm sure the hardware can just as easily signal zeros.


It can't.


Re: AST Macros?

2012-06-04 Thread Don Clugston

On 01/06/12 21:37, Jacob Carlborg wrote:

On 2012-06-01 17:47, Gor Gyolchanyan wrote:


Where can I read more about Bartosz's race-free type system and if there
are some specific ideas already, AST macros for D as well?


AST macros have been mentioned in the newsgroups several times. There
was a talk at the first D conference mentioning AST macros. This was
before D2.

http://d.puremagic.com/conference2007/speakers.html

It's the talk by Walter Bright and Andrei Alexandrescu. It's probably in
the second part.



AST macros were discussed informally on the day after the conference, 
and it quickly became clear that the proposed ones were nowhere near 
powerful enough. Since that time nobody has come up with another 
proposal, as far as I know.


Re: [Proposal] Additional operator overloadings for multidimentional indexing and slicing

2012-06-04 Thread Don Clugston

On 03/06/12 19:31, tn wrote:

On Friday, 1 June 2012 at 01:57:36 UTC, kenji hara wrote:

I'd like to propose a new language feature to D community.
...
This patch is an additional enhancement of opDollar (issue 3474 and
#442).



Sounds awesome. However, the name opDollar should be changed to
something like opSize, opLength, opEnd or almost anything else
than the current name.


opDollar is a pretty awful name but nobody could come up with something 
that is less awful. At least it is not confusing. Everybody instantly 
knows what it does.
For built-in arrays $ is the length and the size, but that isn't 
generally true.


Wish we had a better name, but opLength isn't it, and nor is opSize.
opEnd might be the best of those three, but it kinda sounds like 
something to do with ranges.


Re: runtime hook for Crash on Error

2012-06-04 Thread Don Clugston

On 01/06/12 12:26, Walter Bright wrote:

On 6/1/2012 1:48 AM, Dmitry Olshansky wrote:

On 01.06.2012 5:16, Walter Bright wrote:

On 5/31/2012 3:22 AM, Dmitry Olshansky wrote:

On 31.05.2012 13:06, deadalnix wrote:

This is called failing gracefully. And this highly recommended, and
you
KNOW that the system will fail at some point.


Exactly. + The point I tried to argue but it was apparently lost:
doing stack unwinding and cleanup on most Errors (some Errors like
stack
overflow might not recoverable) is the best thing to do.


This is all based on the assumption that the program is still in a valid
state after an assert fail, and so any code executed after that and the
data it relies on is in a workable state.


 This is a completely wrong assumption.

To be frank a completely wrong assumption is flat-out exaggeration.
The only
problem that can make it completely wrong is memory corruption.
Others just
depend on specifics of system, e.g. wrong arithmetic in medical
software ==
critical, arithmetic bug in refracted light color component in say
3-D game is
no problem, just log it and recover. Or better - save game and then crash
gracefully.


Except that you do not know why the arithmetic turned out wrong - it
could be the result of memory corruption.


This argument seems to be:

1. There exist cases where you cannot know why the assert failed.
2. Therefore you never know why an assert failed.
3. Therefore it is not safe to unwind the stack from a nothrow function.

Spot the fallacies.

The fallacy in moving from 2 to 3 is more serious than the one from 1 to 
2: this argument is not in any way dependent on the assert occuring in a 
nothrow function. Rather, it's an argument for not having AssertError at 
all.






Re: Exception/Error division in D

2012-06-04 Thread Don Clugston

On 01/06/12 22:35, Walter Bright wrote:

On 6/1/2012 11:14 AM, deadalnix wrote:

We are talking about runing scope statement and finally when unwiding
the stack,
not trying to continue the execution of the program.


Which will be running arbitrary code not anticipated by the assert
failure, and code that is highly unlikely to be desirable for shutdown.


Sorry, Walter, that's complete bollocks.

try {
   assert(x == 2);
} catch(AssertException e)
{
   foo();   
}

is exactly equivalent to:

version (release)
{}
else
{
   if (x!=2) foo();
}

Bad practice, sure. But it's not running arbitrary, unanticipated code.



Re: [Proposal] Additional operator overloadings for multidimentional indexing and slicing

2012-06-04 Thread Don Clugston

On 04/06/12 15:38, bearophile wrote:

David Nadlinger:


Actually, I'd say its the other way round – opDollar rather
corresponds to opDoubleEqualSign, as it simply describes the character
used.


I agree. It's the opposite of the semantic names of the original
operator overloading set.


You mean like the old opStar() (which meant deref), or like opBinary(+) ?

g


Re: Pointer semantics in CTFE

2012-05-31 Thread Don Clugston

On 30/05/12 17:33, Michel Fortin wrote:

On 2012-05-30 14:44:37 +, Steven Schveighoffer
schvei...@yahoo.com said:


On Tue, 29 May 2012 13:35:12 -0400, Michel Fortin
michel.for...@michelf.com wrote:


Personally, I think it'd be much cleaner to go with some kind of
magic function than trying to match the condition against a
predefined pattern. Something like da.isSliceOf(a), which could do
the usual pointer thing at runtime and call some sort of CTFE
intrinsic at compile-time.


That doesn't help when most code does not use this today. I.e. one of
the main benefits of ctfe is that you don't *have* to write special code.


But at the other end, there should be an easy to understand separation
between what is supported by CTFE and what is not. Once you try to add
special cases for some code patterns by adding heuristics, those
heuristics now define the line and would have to become part of the
language specification.

More generally, the drawback of this kind of pattern recognition is that
there's an infinite pool of equivalent patterns to recognize, and
seemingly innocuous changes to a CTFEable function could break its
CTFEablility if they happen to cross the invisible boundary.

I'm just trying to point out the drawbacks of too clever heuristics. If
such an heuristic is used, I think it should be limited in scope and
well documented. Unfortunately, that means you'll still have to care
about writing code in a way that fits the documented pattern. It'd be
much easier to reason about CTFEability if the pattern had to be
encapsulated in its own function.



The heuristic is:  one pointer comparison in each direction, connected 
by  or ||. No restriction on the pointer expressions, except that they 
must have no side-effects.


That covers most legitimate cases.
The ones it doesn't cover are:
- doing two interleaved isInside() comparisons:

p1 = q1  s1 = r1  p2  q2  s2  r2
which needs to be rewritten as:
(p1 = q1  p2  q2)  (s1 = r1  s2  r2)

- saving two one-side compares, and then not using them for _anything_ 
except an  or ||

--- this is a fundamental limitation

- calling two functions which each return a one-side-compare:
bool cmp(void *a, void *b) { return ab);
cmp(p1, q1)  cmp(q2, p2)

 this one could actually be done, because it would only be legal to 
call such a function from an  or ||. Implementation would be 
complicated though.


Re: [OT] Windows users: Are you happy with git?

2012-05-31 Thread Don Clugston

On 30/05/12 21:49, Alex Rønne Petersen wrote:

On 30-05-2012 21:46, Kagamin wrote:

On Friday, 18 May 2012 at 07:58:26 UTC, Lars T. Kyllingstad wrote:

were some concerns about using Git on Windows. People claimed that Git
was a very Linux-centric tool, and that Windows support was buggy at
best.


Of course, git is a Linux-centric tool (Linus wrote it to be inherently
unportable), hacked into windows environment and augmented with msys.


You make it sound as if he was trying to hinder portability. He merely
didn't care. Not the same thing.



He expressed some very strong views to it. Aggression not ambivalence.

I still can't avoid the feeling that if you're on Windows, you're a 
second-class citizen in the git world.



BTW I found what the problem with my installation was: if you manage you 
to have two different git versions installed (I had git installed via 
cygwin, and later installed stand-alone MSYS git) then running one on a 
repository created by the other will corrupt various files in the 
repository, most notably the index file.


It seems that git has no version numbers in its files. Instead, it 
silently corrupts them.




Re: Purity in D – new article

2012-05-30 Thread Don Clugston

On 29/05/12 19:35, David Nadlinger wrote:

On Tuesday, 29 May 2012 at 12:08:08 UTC, Don Clugston wrote:

And to set the record straight -- the relaxed purity ideas were not my
idea.
I forget who first said them, but it wasn't me. I just championed them.


Unfortunately, I don't quite remember either – was it Bruno Medeiros? In
any case, if somebody can help my memory here, I'd be glad to give
credit to the one who came up with the original proposal in the article
as well.

David


The successful proposal, using weakly pure/strongly pure (Sep 21 2010):

http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_Relax_rules_for_pure_117735.html

Its basically the same as this one by Bruno (Apr 29 2008), which uses 
partially pure and mentions an earlier post by me:


http://www.digitalmars.com/d/archives/digitalmars/D/Idea_partially_pure_functions_70762.html#N70762

And the earliest reference I could find is by me (Apr 5 2008) where I 
called it an amoral function.


http://www.digitalmars.com/d/archives/digitalmars/D/Grafting_Functional_Support_on_Top_of_an_Imperative_Language_69253.html

The first compiler release with pure function attributes (though not 
implemented) was released in Apr 22, 2008 and the first with pure as a 
keyword was Jan 20 2008.

So surely this is close to the original.

So now I'm confused, maybe it *was* me after all!
Then formalized by Bruno, and later championed by me?



Re: Pointer semantics in CTFE

2012-05-30 Thread Don Clugston

On 29/05/12 16:20, Michel Fortin wrote:

On 2012-05-29 13:29:35 +, Don Clugston d...@nospam.com said:


On 27/05/12 02:45, Walter Bright wrote:

You could implement it as simply comparing the addresses - you'd be no
worse off than C is, and you would get the correct answer for pointers
both in and out of the array without needing special cases.


I think that's a no-go.
Implementation-specific behaviour at runtime is bad enough, but at
compile time, it's truly horrible. Consider that any change to
unrelated code can change the results. Something that makes it really
terrible is that the same function can be called in CTFE once before
inlining, and once after. Good luck tracking that down.
And at runtime, you have a debugger.


Wouldn't it be possible to just catch the case where you compare two
pointers not assigned from the same memory block and issue an error?

Here's an idea: make each CTFE pointer some kind of struct with a
pointer to the memory block and an offset. When comparing, if the memory
block isn't the same, it's an error. If you add or subtract to a
pointer, it'll still belong to the same memory block but with a
different offset, thus it remains comparable. When dereferencing, you
can make sure the pointer still points inside the block, assuming the
block knows its length.


Thats _exactly_ what it does right now.


Re: CTFE slower than expected

2012-05-30 Thread Don Clugston

On 29/05/12 23:23, Philippe Sigaud wrote:

On Tue, May 29, 2012 at 2:52 PM, Don Clugstond...@nospam.com  wrote:


Is there any way to improve it?



Oh yeah. Orders of magnitude, easily.


!


The slowness is not in any way
inherent to CTFE. The experience will be completely different, once I have
some time to work on it -- I know exactly how to do it.


Did 2.058 or 2.059 see any new code for CTFE? Like the OP, I've the
impression CTFE/mixins suddenly became far slower. I'm not
complaining, I understand it's a difficult part of DMD, but I wondered
if what I see is real or imaginary.


The behaviour of __traits(allMembers) changed (it now returns an array 
of string literals) and I expect that to be a little bit slower.
Compiling Phobos is now *much* slower than it used to be, due to changes 
in Phobos. (eg, import std.random; is unbelievably slow).



As for CTFE, certain cases became faster (eg, repeated use of global 
array literals).


But if you can pinpoint a case where CTFE itself became slower, I'd like 
to know.




Re: Exception/Error division in D

2012-05-30 Thread Don Clugston

On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to be), then
what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing execution
after an Error is considered to be truly _bad_ idea, so in general, why does
it matter whether scope statements, finally blocks, or destructors get
executed? It's only rarer cases where you're trying to do something like
create a unit test framework on top of assert that you would need to catch an
Error, and that's questionable enough as it is. In normal program execution,
an error is fatal, so cleanup is irrelevant and even potentially dangerous,
because your program is already in an invalid state.


That's true for things like segfaults, but in the case of an 
AssertError, there's no reason to believe that cleanup would cause any 
damage.
In fact, generally, the point of an AssertError is to prevent the 
program from entering an invalid state.

And it's very valuable to log it properly.


Re: Pointer semantics in CTFE

2012-05-30 Thread Don Clugston

On 30/05/12 01:47, Mehrdad wrote:

Just a general note: going the make a special case for two comparisons
route won't work if, for example, someone decides to use a lambda for
comparing pointers.


You mean effectively like:

bool cmp(void *x, void *y)
{
   return x  y:
}

assert ( cmp(x, y)  cmp(x, z) );

?
Yes, this is why it's a special case.


I can imagine how that could be implemented in the current CTFE, I 
cannot see how it could be done reasonably with a JIT CTFE implementation.


You'd have to have a special lamba for pointer inside a range rather 
than simple pointer comparisons.


I'm suggesting that is pointer inside a range is a different primitive 
operation from comparison of two pointers to the same memory block.


Even though C code typically uses the latter to implement the former, 
it's relying on undefined behaviour.


Re: Exception/Error division in D

2012-05-30 Thread Don Clugston

On 30/05/12 12:59, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 11:32:00 Don Clugston wrote:

On 30/05/12 10:40, Jonathan M Davis wrote:

On Wednesday, May 30, 2012 10:26:36 deadalnix wrote:

The fact that error don't trigger scope and everything is nonsensial.


If an Error is truly unrecoverable (as they're generally supposed to be),
then what does it matter? Something fatal occured in your program, so it
terminates. Because it's an Error, you can get a stack trace and report
something before the program actually terminates, but continuing
execution after an Error is considered to be truly _bad_ idea, so in
general, why does it matter whether scope statements, finally blocks, or
destructors get executed? It's only rarer cases where you're trying to do
something like create a unit test framework on top of assert that you
would need to catch an Error, and that's questionable enough as it is. In
normal program execution, an error is fatal, so cleanup is irrelevant and
even potentially dangerous, because your program is already in an invalid
state.


That's true for things like segfaults, but in the case of an
AssertError, there's no reason to believe that cleanup would cause any
damage.
In fact, generally, the point of an AssertError is to prevent the
program from entering an invalid state.


An assertion failure really isn't all that different from a segfault. By
definition, if an assertion fails, the program is an invalid state, because the
whole point of the assertion is to guarantee something about the program's
state.


There's a big difference. A segfault is a machine error. The integrity 
of the machine model has been violated, and the machine is in an 
out-of-control state. In particular, the stack may be corrupted, so 
stack unwinding may not be successful.


But, in an assert error, the machine is completely intact; the error is 
at a higher level, which does not interfere with stack unwinding.


Damage is possible only if you've written your destructors/finally code 
extremely poorly. Note that, unlike C++, it's OK to throw a new Error or 
Exception from inside a destructor.
But with (say) a stack overflow, you don't necessarily know what code is 
being executed. It could do anything.




Now, if a segfault occurs (particularly if it's caused by something
other than a null pointer), the program is likely to be in a _worse_ state,
but it's in an invalid state in either case. In neither case does it make any
sense to try and recover, and in both cases, there's a definite risk in
executing any further code - including cleanup code.



Yes, the segfault is
probably worse but not necessarily all that much worse. A logic error can be
just as insidious to the state of a program as memory corruption, depending on
what it is.


I'm surprised by your response, I didn't think this was controversial.
We could just as easily have said assert() throws an AssertException.
(Or have two kinds of assert, one which is an Error and the other merely 
an Exception).




Re: Purity in D – new article

2012-05-29 Thread Don Clugston

On 27/05/12 22:56, David Nadlinger wrote:

Some of you might remember that I have been meaning to write a
comprehensive introduction to design and use of purity for quite some
while now – I finally got around to do so:

http://klickverbot.at/blog/2012/05/purity-in-d/

Feedback and criticism of all kinds very welcome!

David


For the part about floating-point calculations:

As this would be an impractical restriction, in D pure functions are 
allowed to read and write floating point flags
+ (ie, the floating point state is regarded as a variable implicitly 
passed to every pure function).



And to set the record straight -- the relaxed purity ideas were not my idea.
I forget who first said them, but it wasn't me. I just championed them.



Re: Add CTFE execute function

2012-05-29 Thread Don Clugston

On 28/05/12 03:40, Chang Long wrote:

On Saturday, 26 May 2012 at 15:56:38 UTC, Chang Long wrote:

CTFE execute will be very useful on web develop, for example It is
very hard to create a CTFE version template engine with rich feature.
But we can use execute call to transe template file to d code string,
then mixed it to application.

The vibed project is very cool and I want to add my Jade template to
this, but I can't find other way to do it.


You can do a lot with import(filename);



Maybe we also need a compiler option to enable this CTFE io operate
because security.


Let me make myself more clear, what I suggestion is something like this:

mixin( std.process.execute(/usr/bin/template_engine
template_file_path.htm) );





Re: CTFE slower than expected

2012-05-29 Thread Don Clugston

On 29/05/12 12:25, Manu wrote:

I've been trying to work out why my compile times have gone to hell
recently.

I have a lib, it takes 3.5 seconds to compile.
I add one CTFE heavy module, it's not huge, certainly much smaller than
the rest of the app, and it blows out to 18 seconds. I've done some
experiments removing bits and pieces of code, I can isolate the bits
that add seconds to the compile time, but the big offenders are one-line
mixins which use CTFE fairly aggressively to generate the strings they
mix in.




Can anyone comment on CTFE as implemented? Why is it so slow?


You really don't want to know. What it's actually doing is horrific. Bug 
6498.


The reason why it's still like that is that CTFE bugs have kept cropping 
up (mostly related to pointers and especially AAs), which have prevented 
me from doing anything on the performance issue.



It's
certainly not executing a lot of code. I can imagine executing the same
routine in an interpreted language like lua would take milliseconds or
less, not multiple seconds.
What are the bottlenecks?


It's was originally based on the const-folding code used by the 
optimizer. So most of the code was written with totally goals (that 
didn't include performance).



Is there any way to improve it?


Oh yeah. Orders of magnitude, easily. The slowness is not in any way 
inherent to CTFE. The experience will be completely different, once I 
have some time to work on it -- I know exactly how to do it.





Re: Pointer semantics in CTFE

2012-05-29 Thread Don Clugston

On 27/05/12 02:45, Walter Bright wrote:

On 5/26/2012 3:59 AM, Don wrote:

Yes, that's what happens now. But that doesn't help the programmer.

If it is inside, no problem, the expression is true. But if it is not
inside,
the expression is not false -- it's a compile-time error.


Ok, I understand now what you meant.


So you can't use it as a test for if it is inside the same object.

I was confused about how memmove can work in C without relying on
undefined
behaviour. But I just read
http://www.cplusplus.com/reference/clibrary/cstring/memcpy/
which defines it in terms of an intermediate buffer.

So maybe, the current CTFE implementation is _exactly_ consistent with
the C
spec. If that's true, though, I find it pretty incredible that there
is no way
to find out if a pointers points a particular array, even if you have
pointers
to both the start and end of that array.

(OK, I guess you can iterate from start to end, checking for equality,
but ..
bleah .. it's a terrible abstraction inversion).


You could implement it as simply comparing the addresses - you'd be no
worse off than C is, and you would get the correct answer for pointers
both in and out of the array without needing special cases.


I think that's a no-go.
Implementation-specific behaviour at runtime is bad enough, but at 
compile time, it's truly horrible. Consider that any change to unrelated 
code can change the results. Something that makes it really terrible is 
that the same function can be called in CTFE once before inlining, and 
once after. Good luck tracking that down.

And at runtime, you have a debugger.


It's not hard to make it work in all cases of:

one-sided-comparison  one-sided-comparison
one-sided-comparison || one-sided-comparison

one-sided-comparision:
ptr_expression RELOP ptr_expression
! one-sided-comparision

RELOP:
   
   
   =
   =

where ptr_expression is any expression of type pointer.

And by all cases, I really mean all (the code for the four pointer 
expressions need not having anything in common).


It's only when you allow other expressions to be present, that things 
get hairy.


Pointer semantics in CTFE

2012-05-25 Thread Don Clugston
The current implementation of CTFE strictly enforces C pointer 
semantics. One of the restrictions is that you cannot perform ordering 
comparisons between unrelated pointers.
This is important for repeatability: if it was permitted, the results 
would be arbitrary and might vary unpredictably with subtle changes in 
the code, or change between compiler releases.


But, there's an interesting case from bug 7898: the 'inside' operation.
If p and q are pointers to the same array, then (r = p  r = q) is 
true if r points inside that array, and false if it does not.
This seems to be a perfectly reasonable operation: it is completely 
repeatable and safe, regardless of what r points to. But there doesn't 
seem to be any way to rewrite it to avoid the disallowed comparisons.


I could write code to allow this special case in CTFE. There's a bit of 
work to make sure that all the valid cases are detected, because there 
are quite a lot of ways to rewrite it, but it's not too terrible.


But I dunno, I don't like this sort of thing much. Feels a bit clunky.
OTOH it seems like necessary functionality, and I can't see any other 
way of doing it.


Opinions?



Re: Visual D 0.3.32 maintenance release

2012-05-24 Thread Don Clugston

On 13/05/12 21:28, Walter Bright wrote:

On 5/13/2012 5:31 AM, Rainer Schuetze wrote:

With the workflow of bugzilla/svn it was just copy and pasting the diff
into the bug report. I understand it is easier on Walter's side, though.


Yes, it is definitely easier on my side.

But consider that the number of contributions to dmd has increased by at
least a factor of 10 since we moved to github means that, in general,
contributors find it easier, too.


As I've said before -- that is true for DMD but not for Phobos.
Rate of contributions to Phobos is basically the same as when it was in svn.
Would be good to know why.


Re: forcing weak purity

2012-05-24 Thread Don Clugston

On 24/05/12 02:26, Alex Rønne Petersen wrote:

On 23-05-2012 19:16, deadalnix wrote:

Le 23/05/2012 17:29, Don Clugston a écrit :

There's a huge difference between a global collection *may* be
performed from a pure function vs it *must* be possible to force a
global collection from a pure function.



Thank you !


I personally disagree that this should be a rationale to not allow the
latter. D is a systems language and we really should stop trying to
pretend that it isn't. There's a reason we have a core.memory module
that lets us control the GC.



This is all about not exposing quirks of the current implementation.

The way it currently is, would get you to perform a gc before you enter 
the first pure function.
After that, the only possible garbage to collect would have been 
generated from inside the pure function. And that should be very cheap 
to collect.


Re: pure functions calling impure functions at compile-time

2012-05-24 Thread Don Clugston

On 23/05/12 11:41, bearophile wrote:

Simen Kjaeraas:


Should this be filed as a bug, or is the plan that only pure functions be
ctfe-able? (or has someone already filed it, perhaps)


It's already in Bugzilla, see issue 7994 and 6169.


It's just happening because the purity checking is currently being done 
in a very unsophisticated way.



But I think there is a semantic hole in some of the discussions about
this problem. Is a future compile-time JIT allowed to perform
purity-derived optimizations in CTFE?


Some, definitely. Eg.  foo(n) + foo(n)

can be changed to 2*foo(n), where n is an integer, regardless of what 
foo does.


It does need to be a bit conservative, but I think the issues aren't 
CTFE specific. Eg, something like this currently gives an assert at runtime:


pure nothrow void check(int n) pure nothrow
{
  assert(n == 4);
}

void main()
{
check(3);
}

even though check() can do nothing other than cause an error, it still 
cannot be optimized away. But you can get rid of all subsequent calls to 
it, because they'll produce the same error every time.


Re: forcing weak purity

2012-05-23 Thread Don Clugston

On 23/05/12 07:05, Mehrdad wrote:

We should make 'pure' mean strongly pure.

For weakly pure, we could introduce the 'doped' keyword :-D


No, the keyword should be more like @noglobal

I wish people would stop using this weak purity / strong purity 
terminology, it's very unhelpful. (And it's my fault. I've created a 
monster!)


There is absolutely no need for a keyword to mark (strong) purity, and 
weak purity isn't actually pure.


The real question being asked is, do we need something for logical 
purity? Note that we need the same thing for caching.


Or are the cases like this rare enough that we can just fake it with a cast?




Re: forcing weak purity

2012-05-23 Thread Don Clugston

On 23/05/12 05:22, Steven Schveighoffer wrote:

I have come across a dilemma.

Alex Rønne Petersen has a pull request changing some things in the GC to
pure. I think gc_collect() should be weak-pure, because it could
technically run on any memory allocation (which is already allowed in
pure functions), and it runs in a context that doesn't really affect
execution of the pure function.

So I think it should be able to be run inside a strong pure function.


I am almost certain it should not.

And I think this is quite important. A strongly pure function should be 
considered to have its own gc, and should not be able to collect any 
memory it did not allocate itself.


Memory allocation from a pure function might trigger a gc cycle, but it 
would ONLY look at the memory allocated inside that pure function.




Re: forcing weak purity

2012-05-23 Thread Don Clugston

On 23/05/12 15:56, Alex Rønne Petersen wrote:

On 23-05-2012 15:17, Don Clugston wrote:

On 23/05/12 05:22, Steven Schveighoffer wrote:

I have come across a dilemma.

Alex Rønne Petersen has a pull request changing some things in the GC to
pure. I think gc_collect() should be weak-pure, because it could
technically run on any memory allocation (which is already allowed in
pure functions), and it runs in a context that doesn't really affect
execution of the pure function.

So I think it should be able to be run inside a strong pure function.


I am almost certain it should not.

And I think this is quite important. A strongly pure function should be
considered to have its own gc, and should not be able to collect any
memory it did not allocate itself.

Memory allocation from a pure function might trigger a gc cycle, but it
would ONLY look at the memory allocated inside that pure function.


Implementing this on a per-function basis is not very realistic. Some
programs have hundreds (if not thousands) of pure functions.


No, it's not realistic for every function. But it's extremely easy for 
others. In particular, if you have a pure function which has no 
reference parameters, you just need a pointer to the last point a 
strongly pure function was entered. This partitions the heap into two 
parts. Each can be gc'd independently.


And, in the non-pure part, nothing is happening. Once you've done a GC 
there, you NEVER need to do it again.



Not to mention, we'd need some mechanism akin to critical regions to
figure out when a thread is in a pure function during stop-the-world.
Further, data allocated in a pure function f() in thread A must not be
touched by a collection triggered by an allocation inside f() in thread
B. It'd be a huge mess.


Not so. It's impossible for anything outside of a strongly pure function 
to hold a pointer to memory allocated by the pure function.

In my view, this is the single most interesting feature of purity.


And, frankly, if my program dies from an OOME due to pure functions
being unable to do full collection cycles, I'd just stop using pure
permanently. It's not a very realistic approach to automatic memory
management; at that point, manual memory management would work better.


Of course. But I don't see how that's relevant. How the pure function 
actually obtains its memory is an implementation detail.


There's a huge difference between a global collection *may* be 
performed from a pure function vs it *must* be possible to force a 
global collection from a pure function.


The difficulty in expressing the latter is a simple consequence of the 
fact that it is intrinsically impure.


Re: Limit number of compiler error messages

2012-05-22 Thread Don Clugston

On 20/05/12 00:38, cal wrote:

Is there a way to limit the dmd compiler to outputting just the first
few errors it comes across?


No, but the intention of DMD is to generate only one error per bug in 
your code.
If you are seeing a large number of useless errors, please report it in 
bugzilla.

http://d.puremagic.com/issues/show_bug.cgi?id=8082 is a good example.


Re: Bug report severity

2012-05-11 Thread Don Clugston

On 11/05/12 00:28, Mehrdad wrote:

On Thursday, 10 May 2012 at 22:23:15 UTC, Stewart Gordon wrote:

On 10/05/2012 23:12, Mehrdad wrote:

How do you decide if something is 'critical', 'major', 'blocker', or
just 'normal'? Is
there a rule of thumb I could use?


http://d.puremagic.com/issues/page.cgi?id=fields.html#bug_severity

Stewart.


Hmmm... thanks for the link.

I'm having trouble understanding how to apply them, though.

For example, why are these bugs critical?
http://d.puremagic.com/issues/show_bug.cgi?id=5314


Because an error message with no clue of where it happened, is pretty 
much the same as a segfault. It's far more important than any other 
'diagnostic' bug.



http://d.puremagic.com/issues/show_bug.cgi?id=3445


Because this affects the documentation for all of Phobos. It has a huge 
impact. It's far more important than any other 'ddoc' bug.



Are things like wrong error message or wrong documentation
considered to be on par with ICEs?


No, only error messages without line number.


Like, I see an ICE like
http://d.puremagic.com/issues/show_bug.cgi?id=6774

and I wonder why it's not blocker or at least critical...


They have the 'ice' keyword which performs the same job.

The severities are most useful for distinguishing when a bug has a very 
different importance to others in the same category.


Re: Lack of open source shown as negative part of D on Dr. Dobbs

2012-05-10 Thread Don Clugston

On 10/05/12 11:02, Joseph Rushton Wakeling wrote:

Assuming that LLVM is not an acceptable backend despite its permissive
licence, and that the community can't buy out the code, I'd suggest
again the idea of stabilizing the frontend and then synchronizing DMD,
GDC and LDC updates, with all 3 endorsed as equally valid
implementations of the reference standard.


Yes. This is what we need to work towards.




Re: Does D have too many features?

2012-05-09 Thread Don Clugston

On 09/05/12 10:16, Alex Rønne Petersen wrote:

On 08-05-2012 23:48, Sean Kelly wrote:

On May 8, 2012, at 2:31 PM, Jonathan M Davis wrote:


We've previously discussed having _all_ of the C system call
functions from
the various OSes that we support being in druntime, and I very much
think that
that's the right way to go. Phobos and druntime then have whatever
they need
as for as standard C and system call functions go, and anyone who
needs any
which aren't wrapped by Phobos in some manner has them available to
them.
Anyone that doesn't want to use any of those C function directly,
doesn't have
to, but I don't see any reason to hide them just because someone
doesn't want
to use them in their code.

If the problem is that certain C functions end up getting used a lot
when they
should have D wrappers of some kind which better encapsulate their
functionality, then maybe we add the appropriate wrappers to Phobos. But
that's a completely different issue. Hiding the C functions doesn't
help us
any.


I personally use import core.stdc as an indicator that there may be
some feature missing from Phobos. It's easily greppable, and easy to
avoid using the routines. In fact, I think import core anything
should be an exceptional case in a typical D application. Everything
exposed in Druntime is for what I'd consider power users. Unsafe
threads, runtime and GC hooks, platform API calls, etc. It's all there
because the higher-level stuff needs it, but is really not intended
for general use.



I just hope none of it goes away. I make extensive use of many core.*
modules.




It makes sense to make truly internal stuff internal, but the standard C
function declarations and OS system functions are _not_ internal to
druntime.
They're _very_ much external. druntime is just providing them because
they're
functionality which is core to the system that any D program is
running on.


Once upon a time, there was a D runtime library (unrelated to
Druntime) that has no C library dependence at all. It was an
interesting idea, but I don't know that there's any system that D
targets which doesn't support C.


*Is* there any system that doesn't support C? ;)


There are plenty of systems that don't support C99 perfectly.


Re: is operator for structures?

2012-05-09 Thread Don Clugston

On 09/05/12 16:13, bearophile wrote:

Gor Gyolchanyan:


Because the opBinary [...]


Thank for your answer, but I don't carte of why the D compiler accepts
that. I only care about the D compiler statically refusing that.

Bye,
bearophile


I think you're asking for opBinary to be a keyword.
If it were statically rejected, surely you'll also want to have:

void opBinary(string xx, int x) {}

rejected as well. Along with a multitude of other things.


Re: Why not all statement are expressions ?

2012-05-08 Thread Don Clugston

On 07/05/12 19:06, deadalnix wrote:

Hi,

Working on D I noticed that some statement, notably assert, are
expression of type void. Why not all statement (that are not expression
already) are expression ?


assert isn't a statement. It's an expression ( same as is() ). What 
makes you think it's a statement?


The main use for a void expression is so that it can be used in a comma 
expression; this is why assert is an expression.


The curious thing, which may be the source of the confusion, is that 
static assert() is a statement, while assert() is an expression. Maybe 
static assert should also be an expression rather than a statement?


Re: Does D have too many features?

2012-05-08 Thread Don Clugston

On 08/05/12 09:56, Andrej Mitrovic wrote:

On 4/30/12, Andrej Mitrovicandrej.mitrov...@gmail.com  wrote:

Personally my gripe with compilation times is that I get very used to
having fast build times where I can go through an edit+compile+run
cycle really fast, but after a while build times get slower


Also since 2.059 error reporting is *completely* broken. I have to
wait 5 seconds just to get this error message itself to print to the
screen:
http://pastebin.com/y93GEPAf

500 lines of errors even though only the first line is an actual
error. What in the actual fuck are all those other error messages? The
only problem was this line in a main file:
CppGen gen;
and CppGen was undefined because I've missed an import.

And if I remove the only import left (std.range), I get much less
garbage but I still get unrelated errors:
main.d(80): Error: undefined identifier CppGen
D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\conv.d(244): Error:
template std.conv.toImpl does not match any function template
declaration
D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\conv.d(244): Error:
template std.conv.toImpl cannot deduce template function from argument
types !(string)(long)
D:\DMD\dmd2\windows\bin\..\..\src\phobos\std\conv.d(244): Error:
template instance toImpl!(string) errors instantiating template
loader\gcc.d(167): Error: template instance
std.conv.to!(string).to!(long) error instantiating

2.058 error reporting worked fine, I don't know what someone did to
screw this up so massively.


That bug was fixed in git not long after release. Unfortunately it seems 
that there are not enough people doing beta testing.


As for why it happened -- previously the compiler used a hack to prevent 
the flood of error messages (and the hack didn't work properly in the 
case where errors were gagged, like in is(typeof()) ). Now it does it 
properly.





Re: Integer overflow and underflow semantics

2012-05-07 Thread Don Clugston

On 05/05/12 06:57, Alex Rønne Petersen wrote:

Hi,

I don't think the language really makes it clear whether overflows and
underflows are well-defined. Do we guarantee that for any integral type
T, T.max + 1 == T.min and T.min - 1 == T.max?

This is relevant in particular for GDC and LDC since they target a lot
of weird architectures.



I think the reason that C makes no guarantees, was because of 
ones-complement machines (which had become very rare even by 1970).

Surely we can assume 2-s complement behaviour?


Re: Oddness with C binding

2012-05-03 Thread Don Clugston

On 03/05/12 06:28, James Miller wrote:

I'm writing bindings to XCB right now, and its mostly going smoothly.
However I have encountered a very strange problem.

This bit of code segfaults with DMD:

auto connection = xcb_connect(null, null);

auto setup = xcb_get_setup(connection);
auto iter = xcb_setup_roots_iterator(setup);

auto screen = iter.data;

But it doesn't segfault with LDC2. This is odd to me because as far as I
am aware LDC2 uses the same front end at DMD. This must mean that there
is a bug in the dmd backend.

I thought it could be related to const optimizations, but I removed all
the const declarations from the appropriate C bindings and the same
thing happened.

I don't have the time to create a minimal test case for this, so I can't
really file a bug report on it. I was also wondering what could cause
this problem. I am using dmd 2.059 and the latest ldc from the arch
repositories.

--
James Miller


The infamous bug 5570?


Re: How can D become adopted at my company?

2012-05-03 Thread Don Clugston

On 30/04/12 01:03, Manu wrote:

On 30 April 2012 01:24, Tove t...@fransson.se
mailto:t...@fransson.se wrote:

On Sunday, 29 April 2012 at 22:13:22 UTC, Manu wrote:

Is it technically possible to have a precise GC clean up all
unreferenced
memory in one big pass?


yes, but unless it's also moving/compacting... one would suffer
memory fragmentation... so I would imagine TempAlloc is a better fit?


In some cases I'm comfortable with that type of fragmentation (large
regularly sized resources), although that leads me to a gaping hole in
D's allocation system...

OT, but still very important
There is no way to request aligned memory. I can't even specify an
alignment on a user type and expect it to be aligned if I create one on
the stack, let alone the heap _
It seems I can request alignment for items within a struct, but I can't
align the struct its self. In addition, a struct doesn't inherit the
alignment of its aligned members, so the struct is allocated unaligned,
and the aligned member fails its promise anyway.


Bug 2278.


Re: Does D have too many features?

2012-05-03 Thread Don Clugston

On 01/05/12 00:33, Timon Gehr wrote:

On 04/30/2012 11:28 PM, bearophile wrote:

Walter:


The first thing to emphasize is that NONE of this will happen for D2.
The emphasis on D2 is fixing implementation and toolchain issues.
Breaking existing code is off the table unless we are pretty much
forced to in order to fix some other more important issue.


But you need to keep into account that D2 is still a not widely used
language. So deprecating some things now will cause far less troubles
than doing it in D3 some years from now.


D2 - D3 will be full of breaking changes anyway. Otherwise there is no
reason to add another major language version.



What is this D3 thing 
As far as I can tell, 'D3' was invented by newcomers to the forums.


Re: Does D have too many features?

2012-05-03 Thread Don Clugston

On 28/04/12 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?


Other ones which were agreed to a long time ago were:

* NCEG operators

* built-in .sort and .reverse

=

About the NCEG operators -- the reason they're redundant is that you 
practically always want to treat NaN separately.


I've tried _very_ hard to come up with uses for them, but without success.

The thing I've used the most is:
x != x

which is a kind of built-in isNaN(x), but that can also be rewritten as:
x != x

Initially I though you'd do things like

real func(real x)
{
// x must be non-NaN and in the range -x.infinity .. N
  if (x ! N)
  return real.nan;

but even that isn't convincing, because if x is NaN you should be 
returning x, so that you preserve NaN payloads.


I think I have used these guys more than anyone else, but I still 
haven't found a single use case that stands up to scrutiny.




Re: Does D have too many features?

2012-05-03 Thread Don Clugston

On 03/05/12 16:13, Andrei Alexandrescu wrote:

On 5/3/12 9:55 AM, Don Clugston wrote:

On 28/04/12 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?


Other ones which were agreed to a long time ago were:

* NCEG operators

* built-in .sort and .reverse


Good ones. In fact I even discounted them from this discussion because
I'd already considered them gone. Walter agreed that I don't mention
them in TDPL, with the intent to have them peter out.

One good step right now would be to remove NCEG operators from the
online documentation. Later on, we'll consider them an accept-invalid
bug :o).


Well, they are also used in druntime, in core.stdc.math

BTW I *hate* that module, I don't know why it exists. Even worse, it 
seems to be growing -- people are adding more things to it.

Practically everything in there has a better implementation in std.math.


Re: Does D have too many features?

2012-04-30 Thread Don Clugston

On 29/04/12 20:08, Manu wrote:

On 29 April 2012 18:50, Don nos...@nospam.com
mailto:nos...@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.



Re: Does D have too many features?

2012-04-30 Thread Don Clugston

On 30/04/12 05:45, H. S. Teoh wrote:

On Sun, Apr 29, 2012 at 04:40:37PM +0200, Jacob Carlborg wrote:
[...]

* Do-while loops, how useful are those actually?


I grepped through the DMD source once, looking for how often Walter uses 
do..while. The answer: exactly zero.




OK, that got me all riled up about looping constructs, and now I'm
provoked to rant:

Since the advent of structured programming, looping constructs have
always been somewhat b0rken. Yes they worked very well, they are clean,
powerful, gets rid of almost all cases of needing goto's, etc.. But the
point of a loop is that *the entry point does not always correspond with
the exit point (where the loop condition is tested)*. The problem with
both do-loops and while-loops is that they are just straitjacketed
versions of a more general looping construct.


Completely agree. Forth is one of the few languages which got it right.

BEGIN

cond WHILE
...
REPEAT



Re: Does D have too many features?

2012-04-30 Thread Don Clugston

On 30/04/12 12:27, Manu wrote:

On 30 April 2012 10:32, Don Clugston d...@nospam.com
mailto:d...@nospam.com wrote:

On 29/04/12 20:08, Manu wrote:

On 29 April 2012 18:50, Don nos...@nospam.com
mailto:nos...@nospam.com
mailto:nos...@nospam.com mailto:nos...@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.


Re: What to do about default function arguments

2012-04-26 Thread Don Clugston

On 26/04/12 05:44, Walter Bright wrote:

A subtle but nasty problem - are default arguments part of the type, or
part of the declaration?

See http://d.puremagic.com/issues/show_bug.cgi?id=3866

Currently, they are both, which leads to the nasty behavior in the bug
report.

The problem centers around name mangling. If two types mangle the same,
then they are the same type. But default arguments are not part of the
mangled string. Hence the schizophrenic behavior.

But if we make default arguments solely a part of the function
declaration, then function pointers (and delegates) cannot have default
arguments. (And maybe this isn't a bad thing?)


I think it is a mistake to allow default arguments in function pointers 
and delegates (it's OK for delegate literals, there you have the 
declaration).

I don't see how it can possibly work.

If it's really a type, then given:
void foo(int x = 2) {}
void bar(int y = 3) {}
then typeof(foo) should be:   void function (int __param0 = 2)
I don't see how we could justify having those types and not using them.

But then, if you have:
auto p = foo;  //  p has default parameter of 2
p = bar; // Should this work?

I really don't think we want this.


As I vaguely remember someone saying about the bug report, it looks like 
an attempt to have a pathetic special case of currying syntax sugar 
built into the language.
But it isn't even as efficient as a library solution (if the 
construction of the default parameter is expensive, it will generate 
gobs of code every time the function parameter is called).


Re: How can D become adopted at my company?

2012-04-26 Thread Don Clugston

On 25/04/12 17:38, Joseph Rushton Wakeling wrote:

On 25/04/12 16:58, Kagamin wrote:

On Tuesday, 24 April 2012 at 14:05:14 UTC, bearophile wrote:

Python was widely used before Google support. And I think Haskell has
enjoyed corporate support for a lot of time.


And who's behind PHP?


... but importantly, Python and PHP (and Ruby, and Haskell, and others)
were fully open source in their reference implementations from the
get-go, or at least from very early on. This isn't just important in
itself, but has a multiplicative impact with inclusion in the Linux
distros, BSD's, etc. which make up the server infrastructure of the web.

It also enables all sorts of 3rd-party suppliers who feel comfortable
including the software in their hosting provision because they can be
certain they won't in future suffer from the commercial constraints of a
proprietary supplier.

D's reference implementation _still_ isn't fully open source -- only the
frontend -- and the available open source compilers lag behind the
reference.


rant
open source is a horrible, duplicitous term. Really what you mean is 
the license is not GPL compatible.

/rant

Based on my understanding of the legal situation with Symantec, the 
backend CANNOT become GPL compatible. Stop using the word still, it 
will NEVER happen.


Re: What to do about default function arguments

2012-04-26 Thread Don Clugston

On 26/04/12 11:28, Timon Gehr wrote:

On 04/26/2012 10:51 AM, Don Clugston wrote:

On 26/04/12 05:44, Walter Bright wrote:

A subtle but nasty problem - are default arguments part of the type, or
part of the declaration?

See http://d.puremagic.com/issues/show_bug.cgi?id=3866

Currently, they are both, which leads to the nasty behavior in the bug
report.

The problem centers around name mangling. If two types mangle the same,
then they are the same type. But default arguments are not part of the
mangled string. Hence the schizophrenic behavior.

But if we make default arguments solely a part of the function
declaration, then function pointers (and delegates) cannot have default
arguments. (And maybe this isn't a bad thing?)


I think it is a mistake to allow default arguments in function pointers
and delegates (it's OK for delegate literals, there you have the
declaration).


The parenthesised part is in conflict with your other statement.


No it doesn't. A default argument is a delegate literal is part of the 
declaration, not part of the type.


<    1   2   3   >