Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Don Clugston via Digitalmars-d

On Friday, 29 September 2017 at 10:32:02 UTC, Timon Gehr wrote:

On 29.09.2017 11:12, Don Clugston wrote:

Guess what this prints


import std.stdio;

void main()
{
   int i = 0;

   switch (i) for (i = 8; i < 10; ++i)
   {
     case 7:
     writeln(i);
     return;

     default: ;
   }
}



Why does this even compile? It's because the grammar is:

SwitchStatement:
     switch ( Expression ) ScopeStatement


and ScopeStatement allows almost anything.
I think the only sane grammar is

SwitchStatement:
     switch ( Expression ) BlockStatement

Initially I thought ScopeStatement was accepted in order to 
enable Duff's device, but it isn't necessary for that. It 
might have originally accepted ScopeStatement to support


E e; switch( e ) with (E) {  }

Or it may have just been an accident.


It is very likely that this part of the grammar was 
deliberately copied from C. It's also consistent with how all 
other control flow constructs are parsed.


But regardless of the original motivation, it allows some 
truly dreadful semantics.


I don't see what your proposed grammar change accomplishes:

switch(i){
for(i=8;i<10;++i){
case 7:
writeln(i);
return;
default:{}
}
}

I.e., you seem to have misidentified the culprit. Whether or 
not to the curly braces are required by the parser has nothing 
to do with switch semantics.


That case looks quite different to me.
It's rather more obvious that the `for` statement has been 
skipped.


The problem I have with the original example is that it looks as 
though the body of the `for` loop is the body of the switch 
statement.





Can we disallow this silliness please?



Maybe this specific case can be disallowed during semantic (but 
I don't really see why it helps, it mostly just makes the 
language definition more complex).


I believe it makes it simpler. You cannot avoid the reference to 
BlockStatement.

Note that:  "A switch statement must have a default statement."

This is only possible only in two situations.

1. Silly degenerate case.
 switch (i) default: ;

2. A statement which contains a BlockStatement.

It accepts unreachable code.

  switch (i) if ( foo() ) {} else { default: ; }

A switch statement followed by anything other than a 
BlockStatement is *always* wrong. Always.


We improved the switch statement a lot by disallowing implicit 
fallthrough. But it still allows other nonsense that was 
presumably inherited from the very early days of K C.


This example just struck me as exceedingly silly, and quite 
misleading.





D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Don Clugston via Digitalmars-d

Guess what this prints


import std.stdio;

void main()
{
  int i = 0;

  switch (i) for (i = 8; i < 10; ++i)
  {
case 7:
writeln(i);
return;

default: ;
  }
}



Why does this even compile? It's because the grammar is:

SwitchStatement:
switch ( Expression ) ScopeStatement


and ScopeStatement allows almost anything.
I think the only sane grammar is

SwitchStatement:
switch ( Expression ) BlockStatement

Initially I thought ScopeStatement was accepted in order to 
enable Duff's device, but it isn't necessary for that. It might 
have originally accepted ScopeStatement to support


E e; switch( e ) with (E) {  }

Or it may have just been an accident.
But regardless of the original motivation, it allows some truly 
dreadful semantics.

Can we disallow this silliness please?



Re: Exception chaining and collectException

2017-08-18 Thread Don Clugston via Digitalmars-d

On Friday, 18 August 2017 at 03:31:38 UTC, Walter Bright wrote:
Chained exceptions are a good idea, but are more or less a 
disaster:


1. No other language does chained exceptions

2. Attempting to hammer D chained exceptions into other 
language schemes (such as C++) makes for lots of unfun hours 
attempting to decode undocumented behavior in those other 
schemes


3. Makes D exceptions incompatible with other language 
exceptions and their infrastructure


4. Are incomprehensibly implemented (I defy anyone to explain 
how the test cases in the test suite are actually supposed to 
work)


Well, I wrote them, so I can explain that. The problem is that 
the idea that you can form a "chain" of exceptions turns out to 
be naive.


What if a chained exception needs to get chained to another 
chained exception? And that then needs to be chained to another 
exception?

It forms a tree! That's why the test cases are so complicated.

So to a large extent, this extremely obscure corner case destroys 
the elegance of the concept.


Secondly, exception handling in windows is practically 
undocumented. Certainly it's not documented in a single place. 
When I began to implement it, I feared it might be impossible. 
There isn't any guarantee that exception chaining can actually be 
implemented on all platforms.



5. Are more or less incompatible with non-GC memory allocation

I'd like to remove them from D.

I recommend *not* designing any program that requires them.


I invested quite a lot personally in implementing chained 
exceptions. But I agree with you.
I was actually quite proud that I worked out the nasty corner 
cases during the initial implementation. As far as I can tell, 
problems with chained exceptions are not because of bugs and 
implementation issues, but because of problems with the concept 
itself.


I think it's just a bit too clever.




Re: Battle-plan for CTFE

2016-05-17 Thread Don Clugston via Digitalmars-d-announce

On Sunday, 15 May 2016 at 12:17:30 UTC, Daniel Murphy wrote:

On 15/05/2016 9:57 PM, Martin Nowak wrote:

On 05/15/2016 01:58 PM, Daniel Murphy wrote:
The biggest advantage of bytecode is not the interpreter 
speed, it's
that by lowering you can substitute VarExps etc with actual 
references

to memory without modifying the AST.

By working with something lower level than the AST, you 
should end up

with something much less complex and with fewer special cases.


Which is a bad assessment, you can stick variable indexes into
VarDeclaration (we already do that) and thereby access them in 
O(1).
Converting control flow and references into byte code is far 
from

trivial, we're talking about another s2ir and e2ir here.

-Martin



For simple types that's true.  For more complicated reference 
types...


Variable indexes are not enough, you also need heap memory, but 
slices and pointers (and references) can refer to values either 
on the heap or the stack, and you can have a slice of a member 
static array of a class on the stack, etc.  Then there are 
closures...


Neither e2ir or s2ir are actually that complex.  A lot of the 
mess there comes from the backend IR interface being rather 
difficult to work with.
 We can already save a big chunk of complexity by not having to 
translate the frontend types.  E.g.  implementing the logic in 
the interpreter to correctly unwind through destructors is 
unlikely to be simpler than lowering to an IR.


Exactly. I think the whole idea of trying to avoid a glue layer 
is a mistake.
CTFE is a backend. It really is. And it should be treated as one. 
A very simple one, of course.
Once you do this, you'll find all sorts of commonalities with the 
existing glue layers.
We should end up with at least 4 backends: DMD, GCD, LDC, and 
CTFE.


Many people here are acting like this is something complicated, 
and making dangerous suggestions like using Phobos inside the 
compiler. (I think everyone who has fixed a compiler bug that was 
discovered in Phobos, will know what a nightmare that would be. 
The last thing compiler development needs is another level of 
complexity in the compiler).


As I've tried to explain, the problems with CTFE historically 
were never with the CTFE engine itself. They were always with the 
interface between CTFE and the remainder of the compiler -- 
finding every case where CTFE can be called, finding all the 
bizarre cases (tuple variables, variables without a stack because 
they are local variables declared in comma expressions in global 
scope, local 'ref' variables, etc), finding all the cases where 
the syntax trees were invalid...


There's no need for grandiose plans, as if there is some 
almost-insurmountable problem to be solved. THIS IS NOT 
DIFFICULT. With the interface cleaned up, it is the well-studied 
problem of creating an interpreter. Everyone knows how to do 
this, it's been done thousands of times. The complete test suite 
is there for you. Someone just needs to do it.


I think I took the approach of using syntax trees about as far as 
it can go. It's possible, but it's really vile. Look at the code 
for doing assignments. Bleagh. The only thing in its favour is 
that originally it was the only implementation that was possible 
at all. Even the first, minimal step towards creating a ctfe 
backend -- introducing a syntax-tree-validation step -- 
simplified parts of the code immensely.


You might imagine that it's easier to work with syntax trees than 
to start from scratch but I'm certain that's not true. I'm pretty 
sure that the simplest approach is to use the simplest possible 
machine-independent bytecode that you can come up with. I had got 
to the point of starting that, but I just couldn't face doing it 
in C++.


TL;DR:  CTFE is actually a backend, so don't be afraid of 
creating a glue layer for it.





Re: Battle-plan for CTFE

2016-05-13 Thread Don Clugston via Digitalmars-d-announce

On Monday, 9 May 2016 at 16:57:39 UTC, Stefan Koch wrote:

Hi Guys,

I have been looking into the DMD now to see what I can do about 
CTFE.

Unfortunately It is a pretty big mess to untangle.
Code responsible for CTFE is in at least 3 files.
[dinterpret.d, ctfeexpr.d, constfold.d]
I was shocked to discover that the PowExpression actually 
depends on phobos! (depending on the exact codePath it may or 
may not compile...)


Yes. This is because of lowering. Walter said in his DConf talk 
that lowering was a success; actually, it's a quick-and-dirty 
hack that inevitably leads to a disaster.

Lowering always needs to be reverted.

which let to me prematurely stating that it worked at ctfe 
[http://forum.dlang.org/thread/ukcoibejffinknrbz...@forum.dlang.org]


My Plan is as follows.

Add a new file for my ctfe-interpreter and update it gradually 
to take more and more of the cases the code in the files 
mentioned above was used for.


Do Dataflow analysis on the code that is to be ctfe'd so we can 
tell beforehand if we need to store state in the ctfe stack or 
not.


You don't need dataflow analysis. The CtfeCompile pass over the 
semantic tree was intended to determine how many variables are 
required by each function.


Or baring proper data-flow analysis: RefCouting the variables 
on the ctfe-stack could also be a solution.


I will post more details as soon as I dive deeper into the code.


The current implementation stores persistent state for every 
ctfe incovation.
While caching nothing. Not even the compiled for of a function 
body.

Because it cannot relax purity.


No. Purity is not why it doesn't save the state. It's because of 
history.


I think I need to explain the history of CTFE.
Originally, we had constant-folding. Then constant-folding was 
extended to do things like slicing a string at compile time. 
Constant folding leaks memory like the Exxon Valdez leaks oil, 
but that's OK because it only ever happens once.
Then, the constant folding was extended to include function 
calls, for loops, etc. All using the existing constant-folding 
code. Now the crappy memory usage is a problem. But it's OK 
because the CTFE code was kind of proof-of-concept thing anyway.


Now, everyone asks, why doesn't it use some kind of byte-code 
interpreter or something?
Well, the reason is, it just wasn't possible. There was actually 
no single CTFE entry point. Instead, it was a complete mess. For 
example, with template arguments, the compiler would first try to 
run CTFE on the argument, with error messages suppressed. If that 
succeeded, it was a template value argument. If it generated 
errors, it would then see if was a type. If that failed as well, 
it assumed it was a template alias argument.
The other big problem was that CTFE was also often called on a 
function which had semantic errors.


So, here is what I did with CTFE:
(1) Implement all the functionality, so that CTFE code can be 
developed. The valuable legacy of this, which I am immensely 
proud of, is the file "interpret3.d" in the test suite. It is 
very comprehensive. If an CTFE implementation passes the test 
suite, it's good to go.
The CTFE implementation itself is practically worthless. It's 
value was to get the test suite developed.


(2) Created a single entry point for CTFE. This involved working 
out rules for every place that CTFE is actually required, 
removing the horrid speculative execution of CTFE.
It made sure that functions had actually been semantically 
analyzed before they were executed (there were really horrific 
cases where the function had its semantic tree modified while it 
was being executed!!)
Getting to this point involved about 60 pull requests and six 
months of nearly full-time work. Finally it was possible to 
consider a byte-code interpreter or JITer.


We reached this point around Nov 2012.

(3) Added a 'ctfeCompile' step which runs over the semantic tree 
the first time the function is executed at compile time. Right 
now it does nothing much except that check that the semantic tree 
is valid. This detected many errors in the rest of the compiler.


We reached this point around March 2013.

My intention was to extend the cfteCompile step to a byte-code 
generator. But then I had to stop working on it and concentrate 
on looking after my family.


Looking at the code without knowing the history, you'll think, 
the obvious way to do this would be with a byte-code generator or 
JITer, and wonder why the implementation is so horrible. But for 
most of the history, that kind of implementation was just not 
possible.
People come up with all these elaborate schemes to speed up CTFE. 
It's totally not necessary. All that's needed is a very simple 
bytecode interpreter.






D's Greatest Bugbear

2012-12-18 Thread Don Clugston

Bearophile has just entered his 1000th bug report into Bugzilla.
This is more than the three next most prolific contributers, combined.

The top ten bug reporters are (courtesy of Deskzilla):

1002 Bearophile

 315 Andrej Mitrovic
 308 Don Clugston
 282 David Simcha

 193 Andrei Alexandrescu
 185 Jonathon M Davis
 176 Kenji Hara

 156 Timon Gehr
 155 Thomas Kühne
 141 Max Samukha
---
There are only 9 others who have reported 100 bugs or more,
and only another 19 who have reported 50 or more.

So, if you are wondering why the number of open bugs has continued
to climb despite a massive increase in the rate of bugfixing, now you 
know. What it really means is that we're getting a lot of bugs being 
reported, which normally wouldn't be found for a couple of years.


Congratulations, Bugbear!


Re: half datatype?

2012-11-20 Thread Don Clugston

On 18/11/12 12:21, Manu wrote:

I've often wondered about having an official 'half' type.
It's very common in rendering/image processing, supported by most video
cards (so compression routines interacting with this type are common),
and it's also supported in hardware by some cpu's.

ARM for instance supports 'half's in hardware, and GCC has an __fp16
type which would map nicely if D supported the type in the front end.

The alternative us to use ushort everywhere, which is awkward, because
it is neither unsigned, nor is it an integer, and it's not typesafe
(allows direct assignment to ints and stuff)...
It would be nice if: cast(half)someFloat would yield the proper value,
even if it is performed in software in most architectures, it could be
mapped to hardware for those that do it.

It could be done in a library, but then GCC couldn't map it properly to
the hardware type, and since D has no way to describe implicit casts
(that I know of?) it becomes awkward to use.
someFloat = someHalf - doesn't work, because a cast operator expects an
explicit cast, even though this is a lossless conversion and should be
exactly the same as someDouble = someFloat.

Thoughts?


I suspect that what you want in nearly all cases is conversion from

half[] - float[]

ie, a pack/unpack operation. I think it would be quite rare to want to 
operate on a single half.


Although it's supported natively on GPUs, for D's purposes it is more 
natural to view it as compressed data.


Re: A simple question

2012-11-16 Thread Don Clugston

On 16/11/12 05:15, Rob T wrote:

On Friday, 16 November 2012 at 03:41:45 UTC, Stugol wrote:

Event_t e2;// Will compile!


Yeah but that kinda blows, doesn't it?



I found it surprising or unintuitive that the !() is required, and I do
want to know what is the reasoning behind it,


One of the oldest open enhancement requests is on this topic:

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

I don't what the reason is. It'd be interesting to revive the patch 
there, and see if it passes the compiler test suite.


Re: What's the deal with __thread?

2012-11-15 Thread Don Clugston

On 14/11/12 23:16, Walter Bright wrote:

On 11/14/2012 12:06 PM, Sean Kelly wrote:

On Nov 14, 2012, at 6:26 AM, Don Clugston d...@nospam.com wrote:


IIRC it was used prior to 2.030. In the spec, it is in the keyword list,
and it's also listed in the Migrating to shared article. That's all.
There are a small number of uses of it in the DMD test suite.

Is it still valid? Is it useful? Or has everyone forgotten that it still
exists?


I think __thread was for explicit TLS before TLS became the default.
I don't
see a continued use for it.



Sean's right.


Good, that's what I thought. Lets remove it from the spec, and deprecate 
it. There is probably no extant code that uses it, outside of the test 
suite.


However, there is one case in the test suite which is unclear to me:

extern(C) __thread int x;

Is there any other way to do this?




Re: What's the deal with __thread?

2012-11-15 Thread Don Clugston

On 15/11/12 11:54, Walter Bright wrote:

On 11/15/2012 2:28 AM, Don Clugston wrote:

However, there is one case in the test suite which is unclear to me:

extern(C) __thread int x;

Is there any other way to do this?


extern(C) int x;



What about extern(C) variables which are not thread local?
(which I think would be the normal case).
Then from a C header,

extern(C) int x;

must become:

extern(C) __gshared int x;

in D. It's a very rare case, I guess, but it's one of those situations 
where D code silently has different behaviour from identical C code.


Re: hashed array?

2012-11-14 Thread Don Clugston

On 12/11/12 20:42, Jonathan M Davis wrote:

On Monday, November 12, 2012 11:36:38 H. S. Teoh wrote:

I contend that the problem with built-in AA's is their implementation,
not the fact that they're built-in.


Oh, I agree, but we, as a group, have obviously failed to handle the
implementation of the built-in AAs properly, and I think that the indications
are definitely that it's harder to get the built-in AAs right that it would be
to create a library solution.


I disagree with that 100%.
Built-in AAs in D1 work fine (They could use a lot of improvement, but 
there's nothing wrong with the basic approach, it's quite simple). It 
was the idea that they could be seamlessly moved to a library type that 
was an unmitigated disaster.


And for some reason, there has been a refusal to roll it back to the old 
method which worked.


The thing that really really should change is the bizarre 'magic null' 
semantics of AAs.


What's the deal with __thread?

2012-11-14 Thread Don Clugston
IIRC it was used prior to 2.030. In the spec, it is in the keyword list, 
and it's also listed in the Migrating to shared article. That's all. 
There are a small number of uses of it in the DMD test suite.


Is it still valid? Is it useful? Or has everyone forgotten that it still 
exists?


Re: Compilable Recursive Data Structure ( was: Recursive data structure using template won't compile)

2012-11-13 Thread Don Clugston

On 13/11/12 06:51, Rob T wrote:

On Monday, 12 November 2012 at 14:28:53 UTC, Andrej Mitrovic wrote:

On 11/12/12, Andrej Mitrovic andrej.mitrov...@gmail.com wrote:

On 11/12/12, Don Clugston d...@nospam.com wrote:

Yeah. Though note that 1000 bug reports are from bearophile.


Actually only around 300 remain open:
http://d.puremagic.com/issues/buglist.cgi?query_format=advancedemailreporter2=1emailtype2=substringorder=Importancebug_status=UNCONFIRMEDbug_status=NEWbug_status=ASSIGNEDbug_status=REOPENEDbug_status=VERIFIEDemail2=bearophile




Oh wait, that's only for DMD. It's 559 in total:
http://d.puremagic.com/issues/buglist.cgi?query_format=advancedemailreporter2=1emailtype2=substringorder=Importancebug_status=UNCONFIRMEDbug_status=NEWbug_status=ASSIGNEDbug_status=REOPENEDbug_status=VERIFIEDemail2=bearophile



Issue 8990 and 6969, both related to this thread and unresolved, are not
in the list, so I suspect there's a lot more missing too.

PS: I could not figure out how to make a useful report using that bug
report tool either.

--rt


I recommend deskzilla lite. D is on its list of supported open-source 
projects. It maintains a local copy of the entire bugzilla database, so 
you're not restricted to the slow and horrible html interface.







Re: Compilable Recursive Data Structure ( was: Recursive data structure using template won't compile)

2012-11-12 Thread Don Clugston

On 10/11/12 08:53, Rob T wrote:

On Saturday, 10 November 2012 at 06:09:41 UTC, Nick Sabalausky wrote:

I've gone ahead and filed a minimized test case, and also included your
workaround:
http://d.puremagic.com/issues/show_bug.cgi?id=8990

I didn't make that one struct nested since that's not needed to
reproduce the error.


Thanks for filing it.

Looking at the bug reports, there's 2000+ unresolved? Yikes.

--rt


Yeah. Though note that 1000 bug reports are from bearophile.


Re: deprecate deprecated?

2012-11-08 Thread Don Clugston

On 07/11/12 00:56, Walter Bright wrote:

I know there's been some long term unhappiness about the deprecated
attribute - it's all-or-nothing approach, poor messages, etc. Each
change in it changes the language and the compiler.

Perhaps it could be done with a user defined attribute instead?

Anyone want to take on the challenge?


That *cannot* fix the problem.
The problem is not with the deprecated attribute at all, it's with the 
command line switches.


Re: a small study of deprecate

2012-11-08 Thread Don Clugston

On 07/11/12 14:16, monarch_dodra wrote:

There is some talk going on right now of changing deprecate into a
UDA. There are some people saying that deprecate is broken, and
proposing some fixes (myself included). Instead of concentrating on how
to fix it, and like to first study what is broken.


What exactly is supposed to be the lifetime of a deprecated function?
What (default) behavior do we expect from deprecated?

**Timeline**
1. The function can be used normally.
Nothing to say here.

2. The function is *marked* for deprecation.
At this point, the user would like to be served with a warning, that he
should consider migrating to a new function.

3. The function is fully deprecated. At this point, the user shouldn't
be using it anymore, but if he really really wants to, he should be able
to.

4. The function is blasted out of existenc.


The problem, IMO, comes from the fact that we actually have no way to
implement 2. Because of this, there is a major gap in our deprecation
process.


You are quite wrong. The problem is 3. There's actually nothing wrong 
with deprecated, the problem is the -d command line option.
Suppose you want to continue using the function. There is no reasonable 
way of doing it. If you use the -d option, you will not be notified 
about 2. If something else is deprecated, you won't find out about it.


Basically -- a warning should ALWAYS be printed for deprecated 
functions, even if you are using -d. It's that simple.


There is a pull request to fix this situation. I don't know why this 
discussion is happening.


Re: One old problem with associative arrays

2012-11-07 Thread Don Clugston

On 07/11/12 05:38, H. S. Teoh wrote:

On Wed, Nov 07, 2012 at 05:08:43AM +0100, bearophile wrote:
[...]

So the associative array is updated before taking its length. I
suggest to try to fix this AA behavour before too much D2 code relies
on this. I'd like to avoid this to become a permanent wart of D2.

My bug report is from February 2010, it's in the most important 20
bug reports of mine. In my opinion it's wrong to add new features to
D before similar bugs are fixed:

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

[...]

I'd love to fix AA's once for all. The problem is that right now the AA
code is scattered all over the compiler, and even within druntime it's a
schizophrenic mosaic of half-duplicated code, partly in aaA.d and partly
in object_.d. It's a major undertaking even just to refactor this code
in a sane way.

Would you like to help in this effort? ;-)

I tried to do it myself some time ago, and I did get as far as a struct
that works pretty much like the built-in AA's with quite a good number
of current issues fixed, but it got stuck with handling const, pure,
IFTI bugs, and a number of related issues.  Frankly, at this point I
believe that it's going to take more than one person to do it. We need a
team of about 2-3 to tackle different aspects of it so that we can clean
up the whole thing properly. My code is already up on github, but so far
it seems that no one has been interested to contribute yet.

I do agree that cleaning up AA's should be quite an important item in
D2. There are quite a lot of IMO serious problems with the current
implementation. But it ain't gonna happen unless more people help.


T



I keep getting hurt by the bizarre magic null that happens with AAs. 
It makes the implementation really horrible.
Can we please please make it so that declaring an AA creates an empty 
AA? So that AAs are always reference types.
(It would also be OK if they had to explicitly created, just like 
classes are; but these semantics of inserting an item into a null AA 
creates the AA first is really awful).


Making AAs nicer and less bug-prone for users would make them easier to 
implement!




Re: D is a cool language!

2012-11-05 Thread Don Clugston

On 04/11/12 15:30, stonemaster wrote:

On Thursday, 1 November 2012 at 15:56:24 UTC, Tobias Pankrath wrote:

On Thursday, 1 November 2012 at 15:20:11 UTC, Andrei Alexandrescu wrote:

On 11/1/12 9:47 AM, Paulo Pinto wrote:

Hi everyone,

I just saw this online.


The German magazine c't kompakt has an article about cool(exotic)
programming languages, Smalltalk, Haskell and D.

Personally, I like all of them.

Here is the link for the German speaking developers.

http://www.heise.de/newsticker/meldung/Das-neue-c-t-kompakt-Programmieren-kann-bestellt-werden-1739221.html



--
Paulo


Would love to read that. Far as I understand the article (Exotische
Sprache) is not freely available, is that correct?

Andrei


You need to buy the hole issue for 7€ here
http://www.heise-shop.de/heise-zeitschriften-vlg-g/ct-kompakt-programmieren_pid_19862609.html


It's DRM protected. I wouldn't expect to much.


I read the print version of the D article and I have to say that I'm
quite disappointed:

- The author seems to be talking about D1.0 but not about any new D2.0
features. As a new D2 user I don't really know about the exact
differences between D1 and D2.
- For example the source code uses char[] as string type which doesn't
compile with the D2 compiler
- Descent is introduced as an IDE but it actually has been dead for
quite some time.
- Dsource.org is mentioned as a source of the D community.
- D features mentioned: dynamic and static arrays with slices, missing
preprocessor, debug/version tags, short overview of delegates  lambdas,
very short paragraph about templates, lazy parameter, design by contract
features (in/out/invariant), inline assembler and scope statements.
- There is also a paragraph about memory managament where D is described
as garbage collector centered but allows manual memory managment using
the delete keyword and overloading new/delete operators (which is
deprecated, right?).
- There are no examples of phobos
- D2 features like UFCS, CTFE or just the powerful type system including
immutable aren't mentioned at all.


Actually CTFE is a D1 feature!


The author draws a very positive conclusion about D in which he states
that D allows to write high-performance code which still looks
maintainable. As target audience he sees C/C++ programmers but also C#
and Java developers.

Anyway I think the article has been written some years ago and was just
warmed up to be included in the special edition of c't. I'll try to
contact the author to point out the things mentioned above.



Cheers,
André







Re: Simple implementation of __FUNCTION

2012-11-05 Thread Don Clugston

On 06/11/12 07:09, Rob T wrote:

On Friday, 2 November 2012 at 22:33:37 UTC, Rob T wrote:

I discovered it fails to compile when inside a function with auto as
the return type.

auto test()
{
   throw new Exception(  mixin(__FUNCTION) );
   return 0;
}

Error: forward reference to test

but this works

int test()
{
   throw new Exception(  mixin(__FUNCTION) );
   return 0;
}

So we're kinda sunk for inclusion in phobos unless this error can be
resolved.

I'll try the enum idea to see if that works.

--rt


An update on this problem. I found out that the error when using auto as
return type has nothing to do with the mixin. The compiler error
persists when you take mixin out and put in the __traits( ... ) code
directly.

Does anyone else think that this is a compiler bug? If it is a bug then
I'll report it in the bug tracker.

--rt


It fails because you're asking for the full function name, before its 
type has been determined. (There's no real return type 'auto', 'auto' 
just means 'work it out for me').


I don't think this is a bug. Although it might be solvable in this 
particular example, in general it's a circular dependency.


eg, if you do:

auto foo()
{
   static if (__FUNCTION == int foo()) { return 'a' }
   return 0;
}
if __FUNCTION is int foo() then it will return a char, which means its 
signature is char foo(). This is a contradiction.








Re: A little Py Vs C++

2012-11-02 Thread Don Clugston

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

On 2012-11-01 23:51, Walter Bright wrote:


What about all your feature requests? I think you've made more than
anyone, by a factor of 10 at least!

:-)

As for Manu's request

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

I've gone over with him why he needs it, and there's no other reasonable
way. He needs it for real code in a real application.


This is quite interesting. Manu comes in from basically nowhere and
fairly quickly manage to convince Walter to implement at least two
feature requests, this one and the SIMD support. I'm not saying that
they shouldn't have been implemented.


He just knows how to convince Walter.
(Hint: use real-world use cases. Arguments from theoretical computer 
science carry almost no weight with Walter).


 Although I think something like

AST macros could possible solve issue 8108 and a whole bunch of other
features, a few already present in the language.


Yes, and they could cure cancer. AST macros can do anything, because 
they are completely undefined. Without even a vague proposal, it seems 
like a rather meaningless term.




Re: A little Py Vs C++

2012-11-02 Thread Don Clugston

On 02/11/12 10:12, Jens Mueller wrote:

Don Clugston wrote:

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

On 2012-11-01 23:51, Walter Bright wrote:


What about all your feature requests? I think you've made more than
anyone, by a factor of 10 at least!

:-)

As for Manu's request

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

I've gone over with him why he needs it, and there's no other reasonable
way. He needs it for real code in a real application.


This is quite interesting. Manu comes in from basically nowhere and
fairly quickly manage to convince Walter to implement at least two
feature requests, this one and the SIMD support. I'm not saying that
they shouldn't have been implemented.


He just knows how to convince Walter.
(Hint: use real-world use cases. Arguments from theoretical computer
science carry almost no weight with Walter).


I think there are lots of issues in the bug tracker which describe real
use cases. The point is that these are more like bugs whereas Manu's
proposals are more like feature requests.

Jens


The SIMD stuff has no workarounds. I don't know of many other feature 
requests in that category.





Re: A little Py Vs C++

2012-11-02 Thread Don Clugston

On 02/11/12 10:01, Jens Mueller wrote:

Jacob Carlborg wrote:

On 2012-11-01 23:51, Walter Bright wrote:


What about all your feature requests? I think you've made more than
anyone, by a factor of 10 at least!

:-)

As for Manu's request

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

I've gone over with him why he needs it, and there's no other reasonable
way. He needs it for real code in a real application.


This is quite interesting. Manu comes in from basically nowhere and
fairly quickly manage to convince Walter to implement at least two
feature requests, this one and the SIMD support. I'm not saying that
they shouldn't have been implemented. Although I think something
like AST macros could possible solve issue 8108 and a whole bunch of
other features, a few already present in the language.


I had the same thought when reading this. Very disappointing. An issue
with zero votes is fixed instead of more important ones. Why do I vote
anyway?
Regarding SIMD I have the feeling that because it is built into the
compiler static vectors have actually failed what they promised. I
thought D proposed a portable way of vector operations such that you
write
float[4] = a[] + b[]
and the compiler generates SIMD code for you.


Not for short vectors. They are more like the builtin operations in 
Fortran, ie designed for large vectors. More for scientific kinds of 
applications than games. (The two applications look superficially 
similar, but in practice they have little in common).


Re: To take a part in development

2012-11-02 Thread Don Clugston

On 02/11/12 14:04, Habibutsu wrote:

I would like to take a part in development of D programming language or
Phobos library.
I opened bugtracker and found some bugs that i could to fix.
Maybe I should read something (specifically for development) or you can
give me some advice before i create first pull request? Thanks



Join the dmd-internals and/or phobos lists at lists.puremagic.com


Re: A little Py Vs C++

2012-11-02 Thread Don Clugston

On 02/11/12 11:57, Jens Mueller wrote:

Peter Alexander wrote:

On Friday, 2 November 2012 at 10:24:34 UTC, Jens Mueller wrote:

Then I have a serious misunderstanding.
I thought D introduced array operations to allow the compiler to
generate efficient vector operations (in the long run), i.e.
generate
SIMD code. Why is this not working out?


It works fine for large vectors. For small vectors, it is
horrendously slow.

The syntax a[] += b[] essentially calls a function which is designed
to work for large vectors. It has to determine alignment, load
everything from memory, do the operations, then store it back.

The SIMD extensions allow you to define variables that are
guaranteed to be aligned and will probably be in the right registers
to start with. Using them, the vectors ops don't need to determine
alignment, and often don't need to do lots of loads/stores.

Both have their purposes.


I see. But can't the alignment problem be solved by using align. Then
have the compiler emits a call that checks for alignment if none was
specified else use a faster version.


No. For SIMD, you cannot afford to have even a single machine 
instruction inserted, or the benefit is entirely lost.





Re: vestigial delete in language spec

2012-11-02 Thread Don Clugston

On 01/11/12 22:21, Dan wrote:

TDPL states
--
However, unlike in C++, clear does not dispose of the object’s
own memory and there is no delete operator. (D used to have a
delete operator, but it was deprecated.) You still can free
memory manually if you really, really know what you’re doing by
calling the function GC.free() found in the module core.memory.
--
The language spec has this example from the section on Struct
Postblits:
--
struct S {
int[] a;// array is privately owned by this instance
this(this) {
  a = a.dup;
}
~this() {
  delete a;
}
}
--

Is the delete call, then per TDPL not necessary? Is it harmful or
harmless?

Also, are there any guidelines for using and interpreting the output of
valgrind on a D executable?

Thanks
Dan


You'll probably have trouble getting much out of valgrind, because it 
doesn't support 80-bit floating instructions, unfortunately.






Re: assert(false, ...) doesn't terminate program?!

2012-10-30 Thread Don Clugston

On 29/10/12 18:38, Walter Bright wrote:

On 10/29/2012 7:51 AM, Don Clugston wrote: On 27/10/12 20:39, H. S.
Teoh wrote:
  On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote:
  On 10/27/12, H. S. Teoh hst...@quickfur.ath.cx wrote:
   writeln(how did the assert not trigger??!!);// how
did we get
  here?!
 
  Maybe related to -release?
  [...]
 
  Haha, you're right, the assert is compiled out because of -release.
 
  But I disassembled the code, and didn't see the auto x = 1/toInt()
  either. Is the compiler optimizing that away?
 
  Yes, and I don't know on what basis it thinks it's legal to do that.

Because x is a dead assignment, and so the 1/ is removed.




Divide by 0 faults are not considered a side effect.


Ah, that's interesting, I didn't know that.



I think the code would be

better written as:

 if (toInt() == 0) throw new Error();

If you really must have a divide by zero fault,

 if (toInt() == 0) divideByZero();

where:

 void divideByZero()
 {
  static int x;
  *cast(int*)0 = x / 0;
 }


And that works because writes to 0 _are_ considered a side-effect?
Is that guaranteed to work?




Re: __traits(compiles,...) = ? is(typeof(...))

2012-10-30 Thread Don Clugston

On 29/10/12 12:03, Jonathan M Davis wrote:

On Monday, October 29, 2012 11:42:59 Zhenya wrote:

Hi!

Tell me please,in this code first and second static if,are these
equivalent?
with arg = 1, __traits(compiles,check(arg);) = true,
is(typeof(check(arg))) = false.


In principle, is(typeof(code)) checks whether the code in there is
syntatically and semantically valid but does _not_ check whether the code
actually compiles. For instance, it checks for the existence of the symbols
that you use in it, but it doesn't check whether you can actually use the
symbol (e.g. it's private in another module).


Not even that. It checks if the expression has a type. That's all.
The expression has be syntactically valid or it won't compile at all. 
But inside is(typeof()) it is allowed to be semantically invalid.


I started using is(typeof()) as a check for compilability, and other 
people used the idea as well. But it only works if you can convert 
compilable into has a type.


Re: Copying with immutable arrays

2012-10-30 Thread Don Clugston

On 29/10/12 07:19, Ali Çehreli wrote:

On 10/28/2012 02:37 AM, Tobias Pankrath wrote:
  the struct
  SwA from above does neither correspond to SA nor to SB, it's imo more
  like SC:
 
  struct SC {
  immutable(int)* i;
  }

Just to confirm, the above indeed works:

struct SC {
 immutable(int)* i;
}

void main()
{
 immutable(SC)[] arr1;
 SC[] arr2 = arr1.dup;// compiles
}

  Now a copy would do no harm, everything that was immutable in the source
  and is still accessable from the copy is immutable, too. Any reason
  (despite of implemenational issues) that this is not how it works?

Getting back to the original code, the issue boils down to whether we
can copy imutable(string[]) to string[]:

import std.stdio;

struct SwA {
 string[] strings;
}

void main()
{
 immutable(SwA)[] arr1;
 writeln(typeid(arr1[0].strings));
}

The program prints the following:

immutable(immutable(immutable(char)[])[])

Translating the innermost definition as string:

immutable(immutable(string)[])

Let's remove the struct and look at a variable the same type as the member:

 immutable(string[]) imm = [ a, b ];
 writeln(typeid(imm));

The typeid is the same:

immutable(immutable(immutable(char)[])[])

So we can concentrate on 'imm' for this exercise. This is the same
compilation error:

 immutable(string[]) imm = [ aaa, bbb ];
 string[] mut = imm;   // -- compilation ERROR

If that compiled, then both 'imm' and 'mut' would be providing access to
the same set of strings. But the problem is, 'mut' could replace those
strings (note that it could not modify the characters of those strings,
but it could replace the whole string):

 mut[0] = hello;

That would effect 'imm' as well. ('imm' is the equivalent of SwA.strings
from your original code.)

Ali


Awesome answer, it's these kinds of responses that make the D community 
so great.






Re: Another day in the ordeal of cartesianProduct

2012-10-29 Thread Don Clugston

On 27/10/12 00:45, H. S. Teoh wrote:

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

:-(

(The code there is called cartesianProd but it's the reduced code, so it
doesn't really compute the cartesian product. But that's where it's
from.)

So far, the outstanding blockers for cartesianProduct are:
1) Compiler bug which causes unittest failure:

std/range.d(4629): Error: variable lower used before set
std/range.d(4630): Error: variable upper used before set

(Jonathan had a pull request with a Phobos workaround for this, which I
_think_ is already merged, but the autotester is still failing at this
point. :-/)

2) Issue 8542 (crosstalk between template instantiations)

3) And now, issue 8900 (zip fails to compile with repeat(char[]))

So there's still no joy for cartesianProduct. :-(

I'm getting a bit frustrated with the Phobos bugs related to ranges and
std.algorithm. I think we need to increase the number of unittests. And
by that I mean, GREATLY increase the number of unittests. Most of the
current tests are merely sanity tests for the most common usage
patterns, most basic types, or tests added as a result of fixed bugs.

This is inadequate.

We need to actively unittest corner cases, rare combinations, unusual
usages, etc.. Torture test various combinations of range constructs.
Algorithms. Nested range constructs. Nested algorithms. Deliberately
cook up nasty tests that try their best to break the code by using
unusual parameters, unusual range-like objects, strange data, etc.. Go
beyond the simple cases to test non-trivial things.  We need unittests
that pass unusual structs and objects into the range constructs and
algorithms, and make sure they actually work as we have been _assuming_
they should.

I have a feeling there are a LOT of bugs lurking in there behind
overlooked corner cases, off by 1 errors, and other such careless slips,
as well as code that only works for basic types like arrays, which
starts breaking when you hand it something non-trivial.  All these
issues must be weeded out and prevented from slipping back in.

Here's a start:

- Create a set of structs/classes (inside a version(unittest) block)
   that are input, forward, bidirectional, output, etc., ranges, that are
   NOT merely arrays.

- There should be some easy way, perhaps using std.random, of creating
   non-trivial instances of these things.  These should be put in a
   separate place, perhaps outside the std/ subdirectory, where they can
   be imported into unittest blocks by std.range, std.algorithm, whatever
   else that needs extensive testing.

- Use these ranges as input for testing range constructs and algorithms.

- For best results, use a compile-time loop to loop over a given
   combination of these range types, and run them through the same set of
   tests. This will improve the currently spotty test coverage.  Perhaps
   provide some templated functions that, given a set of range types
   (from the above structs/classes) and a set of functions, run through
   all combinations of them to make sure they all work. (We run unittests
   separately anyway, we aren't afraid of long-running tests.)


T



I think that unit tests aren't very effective without code coverage.

One fairly non-disruptive thing we could do: implement code coverage for 
templates. Currently, templates get no code coverage numbers.
We could do a code-coverage equivalent for templates: which lines 
actually got instantiated?

I bet this would show _huge_ gaps in the existing test suite.


Re: assert(false, ...) doesn't terminate program?!

2012-10-29 Thread Don Clugston

On 27/10/12 20:39, H. S. Teoh wrote:

On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote:

On 10/27/12, H. S. Teoh hst...@quickfur.ath.cx wrote:

 writeln(how did the assert not trigger??!!);   // how did we get
here?!


Maybe related to -release?

[...]

Haha, you're right, the assert is compiled out because of -release.

But I disassembled the code, and didn't see the auto x = 1/toInt()
either. Is the compiler optimizing that away?


Yes, and I don't know on what basis it thinks it's legal to do that.


Also, is that even a good idea? Shouldn't we be throwing an exception
here instead of trying to trigger integer division by zero (which may
not even terminate the program, depending on the OS, etc.)?


The intention was that it should behave _exactly_ like an integer 
division by zero.


It's bug 8021, BTW.


Re: Very simple SIMD programming

2012-10-24 Thread Don Clugston

On 24/10/12 04:41, bearophile wrote:

I have found a nice paper, Extending a C-like Language for Portable
SIMD Programming, (2012), by Roland L., Sebastian Hack and Ingo Wald:

http://www.cdl.uni-saarland.de/projects/vecimp/vecimp_tr.pdf




They present a simple scalar program in C:

struct data_t {
 int key;
 int other;
};

int search(data_t* data , int N) {
 for (int i = 0; i  N; i++) {
 int x = data[i].key;
 if (4  x  x = 8) return x;
 }
 return -1;
}


I don't know what that code does. I think the if statement is always 
true. Try compiling it in D.


test.d(8): Error: 4  x must be parenthesized when next to operator 
test.d(8): Error: x = 8 must be parenthesized when next to operator 

Making that an error was such a good idea.
g


Re: [proposal] version statements with multiple arguments.

2012-10-24 Thread Don Clugston

On 23/10/12 05:17, 1100110 wrote:

Looking at std.io (hopefully the right version maybe?) I see this:

version(OSX)
{ do something; }
version(Windows)
{ do the same thing as above; }
version(FreeBSD)
{ ditto; }
version(Linux)
{finally do something different; }
and:
version(Windows) version(DigitalMars)
{ something; }


I was rather surprised that this wasn't accepted:
//Error: found '||' when expecting ')'

version(OSX || Windows || FreeBSD)
{ do something; }
version(Linux)
{ do something different; }


The last one could be intuitively described as:
version(Windows  DigitalMars)
{ blah; }


That allows you to create the same bird's nest that you can get with 
#ifdef in C.


See bug 7417 for a different solution that fixes other problems as well.
Just make version declarations behave like bool variable declarations:

version useTheOrdinaryWay = OSX || Windows || FreeBSD;

version dmdWindows = Windows  DigitalMars;
version (dmdWindows) { blah; }






Re: Very simple SIMD programming

2012-10-24 Thread Don Clugston

On 24/10/12 11:33, Timon Gehr wrote:

On 10/24/2012 11:24 AM, Don Clugston wrote:

On 24/10/12 04:41, bearophile wrote:

I have found a nice paper, Extending a C-like Language for Portable
SIMD Programming, (2012), by Roland L., Sebastian Hack and Ingo Wald:

http://www.cdl.uni-saarland.de/projects/vecimp/vecimp_tr.pdf




They present a simple scalar program in C:

struct data_t {
 int key;
 int other;
};

int search(data_t* data , int N) {
 for (int i = 0; i  N; i++) {
 int x = data[i].key;
 if (4  x  x = 8) return x;
 }
 return -1;
}


I don't know what that code does. I think the if statement is always
true.


No, the code is fine.


Oh, you're right. It's crap code though.


Re: long compile time question

2012-10-24 Thread Don Clugston

On 24/10/12 17:39, thedeemon wrote:

On Wednesday, 24 October 2012 at 03:50:47 UTC, Dan wrote:

The following takes nearly three minutes to compile.
The culprit is the line bar ~= B();
What is wrong with this?

Thanks,
Dan

struct B {
  const size_t SIZE = 1024*64;
  int[SIZE] x;
}

void main() {
  B[] barr;
  barr ~= B();
}
-


The code DMD generates for initializing the struct does not use loops,
so it's
xor ecx, ecx
mov [eax], ecx
mov [eax+4], ecx
mov [eax+8], ecx
mov [eax+0Ch], ecx
mov [eax+10h], ecx
mov [eax+14h], ecx
mov [eax+18h], ecx
mov [eax+1Ch], ecx
mov [eax+20h], ecx
mov [eax+24h], ecx
mov [eax+28h], ecx
mov [eax+2Ch], ecx
mov [eax+30h], ecx
mov [eax+34h], ecx
mov [eax+38h], ecx
...

So your code creates a lot of work for the compiler.


That's incredibly horrible, please add to bugzilla.




Re: How mutable is immutable?

2012-10-22 Thread Don Clugston

On 18/10/12 19:43, Timon Gehr wrote:

On 10/18/2012 10:08 AM, Don Clugston wrote:

On 17/10/12 18:02, Timon Gehr wrote:

On 10/17/2012 01:49 PM, Don Clugston wrote:

...

That's the point -- *which* checks are missing from @safe?


Escaping stack data and arbitrarily freeing memory are not operations
found in memory safe languages.


HOW do you propose to check for escaping stack data?



Static escape analysis. Use the 'scope' qualifier to designate
data that is not allowed to be escaped in order to make it modular.


...


The implementation of the 'scope' storage class should be fixed. We
could then require an unsafe cast(scope) to disable prevention of stack
address escaping.


No we can't. f cannot know that the string it has been given is on the
stack. So main() must prevent it from being given to f() in the first
place. How can it do that?



f can know that it mustn't escape it, which is enough.


void foo(bool b, string y)
{
   immutable (char)[4] x = abba;
   string s = b ? x : y;
   f(s);
}

Make it safe.



It is safe if the parameter to f is marked with 'scope'. (and this in
turn obliges f not to escape it.)


Well, OK, but that involves changing the semantics of immutable. You 
could not pass this kind of local immutable to _any_ existing code.

It would render almost all existing code that uses immutable obsolete.

And what do you get in exchange? Practically nothing!



Analyze scope on the expression level.

The analysis would determine that x[] is 'scope'. It would
conservatively propagate this fact to (b ? x[] : y). Then the local
variable 's' will get the 'scope' storage class.

In general, use a fixed-point iteration to determine all local
variables that might refer to scope'd data and prevent that they get
escaped.




Rust's borrowed pointers may give some hints on how
to extend 'scope' to fields of structs.


I think it is more fundamental than that.


As to delete, delete is as unsafe when the involved data is immutable
as when it is mutable. Why require an additional cast in one case?


This is not about safety.
Modifying immutable data breaks the type system. Deleting mutable data
does not.
AFAIK it is safe to implement delete as a call to the
finalizer, followed by setting the memory to T.init.
...



Now I see where you are coming from. This is indeed a safe approach for
references to/arrays of fully mutable value types, but not for delete
in general.

Make sure to treat void* specially though.

struct S{ immutable int x; this(int x){this.x=x;}}

void main()@safe{
 void* s = new S(2);
 delete s;
}

Class instance memory does not have a T.init, because it is not
assigned a T. And even if it was, how would you know at compile time if
the bound instance has any immutable fields?
Should that be a runtime exception?


Probably. Yeah, it's a bit hard if you have a base class, you can't 
statically check if it has immutable members in a derived class.
Or you could be conservative and disallow delete of anything where you 
don't know the exact type at compile time.





Re: D seems interesting, but...

2012-10-22 Thread Don Clugston

On 15/10/12 13:39, Jacob Carlborg wrote:

On 2012-10-15 11:58, Don Clugston wrote:


I tried that on both Windows and Ubuntu, and couldn't get it to work on
either of them. I posted a couple of bug reports eight months ago, and
they still haven't been fixed. Not recommended for anyone who is having
problems with their installation.


I know it's not a perfect tool and it contains bugs but most things do
work. I don't know which issues have been reported by you, but it seems
there's a problem with the -l flag. Running dvm install 2.060
usually works. Could you please point out which issues have been
reported by you.


I don't remember, it's a long time ago. But this was one of them:
https://github.com/jacob-carlborg/dvm/issues/11

Basically it was case of: download, find a bug, find another bug,
think this has already cost me more time than it could ever save me, 
quit now.




I have very limited time to work with D, as I understand most people
here has, and I'm currently working on other projects than DVM since
basically does what I intended it to do when I started the project.

It seems most D installers are broken in one way or another. But the
success rate with DVM seems to be quite high anyway.






Re: Regarding hex strings

2012-10-19 Thread Don Clugston

On 18/10/12 17:43, foobar wrote:

On Thursday, 18 October 2012 at 14:29:57 UTC, Don Clugston wrote:

On 18/10/12 10:58, foobar wrote:

On Thursday, 18 October 2012 at 02:47:42 UTC, H. S. Teoh wrote:

On Thu, Oct 18, 2012 at 02:45:10AM +0200, bearophile wrote:
[...]

hex strings are useful, but I think they were invented in D1 when
strings were convertible to char[]. But today they are an array of
immutable UFT-8, so I think this default type is not so useful:

void main() {
   string data1 = xA1 B2 C3 D4; // OK
   immutable(ubyte)[] data2 = xA1 B2 C3 D4; // error
}


test.d(3): Error: cannot implicitly convert expression
(\xa1\xb2\xc3\xd4) of type string to ubyte[]

[...]

Yeah I think hex strings would be better as ubyte[] by default.

More generally, though, I think *both* of the above lines should be
equally accepted.  If you write xA1 B2 C3 in the context of
initializing a string, then the compiler should infer the type of the
literal as string, and if the same literal occurs in the context of,
say, passing a ubyte[], then its type should be inferred as ubyte[],
NOT
string.


T


IMO, this is a redundant feature that complicates the language for no
benefit and should be deprecated.
strings already have an escape sequence for specifying code-points \u
and for ubyte arrays you can simply use:
immutable(ubyte)[] data2 = [0xA1 0xB2 0xC3 0xD4];

So basically this feature gains us nothing.


That is not the same. Array literals are not the same as string
literals, they have an implicit .dup.
See my recent thread on this issue (which unfortunately seems have to
died without a resolution, people got hung up about trailing null
characters without apparently noticing the more important issue of the
dup).


I don't see how that detail is relevant to this discussion as I was not
arguing against string literals or array literals in general.

We can still have both (assuming the code points are valid...):
string foo = \ua1\ub2\uc3; // no .dup


That doesn't compile.
Error: escape hex sequence has 2 hex digits instead of 4


Re: Regarding hex strings

2012-10-19 Thread Don Clugston

On 19/10/12 16:07, foobar wrote:

On Friday, 19 October 2012 at 13:19:09 UTC, Don Clugston wrote:


We can still have both (assuming the code points are valid...):
string foo = \ua1\ub2\uc3; // no .dup


That doesn't compile.
Error: escape hex sequence has 2 hex digits instead of 4


Come on, assuming the code points are valid. It says so 4 lines above!


It isn't the same.
Hex strings are the raw bytes, eg UTF8 code points. (ie, it includes the 
high bits that indicate the length of each char).

\u makes dchars.

\u00A1 is not the same as xA1 nor is it x00 A1. It's two non-zero 
bytes.


Re: Tricky semantics of ranges potentially numerous Phobos bugs

2012-10-18 Thread Don Clugston

On 17/10/12 23:41, H. S. Teoh wrote:

On Wed, Oct 17, 2012 at 12:55:56PM -0700, Jonathan M Davis wrote:
[...]

I'm increasingly convinced that input ranges which are not forward
ranges are useless for pretty much anything other than foreach. Far
too much requires that you be able to save the current state - and
most stuff _inherently_ requires it such that it's not simply a
question of implementing the function differently.


It's perfectly possible to implement joiner, chain, find, count, cmp,
equal, until, filter, map, reduce, without assuming that the value
returned by .front is persistent. Just to name a few. In fact, it's even
possible to implement cartesianProduct in which one of the ranges is an
input range.  I'd hardly call that useless.



And adding even further restrictions on input ranges just makes it
worse. It actually wouldn't hurt my feelings one whit if we got rid of
the idea of input ranges entirely.


The motivating example for input ranges, at least according to TDPL, is
find(). There's nothing about find() that precludes non-forward input
ranges. A lot would be missing from the usefulness of ranges if we were
forced to only use forward ranges.


[...]

Regardless, there's nothing in how input ranges are currently defined
which indicates that front would ever be invalidated for _any_ type of
range, and ByLine and ByChunk are pretty much the only ranges I've
ever seen which invalidate previous calls to front. So, I don't see
how you could think that they're anything but abnormal.


I can think of quite a few situations in which it's useful to not assume
that the return value of .front is persistent, which I've already
mentioned before: in-place array permutation, reused buffers for complex
computations, etc..



And if you really want to argue that whether front can be invalidated
or not is somehow part of the difference between an input range and a
forward range, then the documentation on that needs to make that
_very_ clear, and it's going to be that much worse to deal with input
ranges which aren't forward ranges.

[...]

I think I'm not so sure about Andrei's lumping input ranges with
persistent return values from .front together with forward ranges. Some
algorithms, like findAdjacent, do not need a forward range, but they do
need a persistent .front. I do not like the idea of artificially
limiting the scope of findAdjacent just because you can't assume input
ranges' .front returns a persistent value. Like somebody else mentioned,
whether .front is transient or not is orthogonal to whether the range is
an input range or a forward range. There can be ranges whose .front is
persistent, but they can't be forward ranges for practical reasons.


Is it actually orthogonal? Is it possible for a forward range to be 
transient?


Or is it an intermediate concept?
TransientInputRange - NonTransientInputRange - ForwardRange





Re: How mutable is immutable?

2012-10-18 Thread Don Clugston

On 17/10/12 18:02, Timon Gehr wrote:

On 10/17/2012 01:49 PM, Don Clugston wrote:

On 01/01/12 13:50, Timon Gehr wrote:

On 01/01/2012 10:40 AM, Denis Shelomovskij wrote:

So, I'm a function `f`, I have an `immutable(type)[]` argument and I
want to store it for my friend `g` in an TLS variable `v`:
---
string v;
debug string sure;

void f(string s) { v = s; debug sure = s.idup; }
void g() { assert(v == sure); }
---
I also store a copy of `s` into `sure` for my friend to ensure
immutable
date hasn't been mutated.
Can my friend's assertion ever fail without breaking a type-system?
Sure. Just consider this:
---
void main() {
auto s = abba.idup;
f(s);
delete s;
g();
}
---
Is it by-design? Looks like deleting immutable (and const because of
implicit conversion) data should be prohibited.
OK. Let `delete` be fixed. Can we still fail?
---
void h() {
immutable(char)[4] s = abba;
f(s);
}
void main() {
h();
g();
}
---
Damn! So, what can we do with it? Not sure, but I have a proposal.

Fix it in language:
* disallow `delete` of const/immutable data
* disallow immutable data on the stack

This makes data really immutable if I don't miss something. Anyway, I
want `immutable` qualified data to be immutable without breaking a
type-system (if one do it, its his own responsibility), so some changes
should be made (IMHO).


You are using unsafe language features to break the type system. That is
not the fault of the type system.

'@safe:' at the top of the program should stop both examples from
working, it is a bug that it does not.


That's the point -- *which* checks are missing from @safe?


Escaping stack data and arbitrarily freeing memory are not operations
found in memory safe languages.


HOW do you propose to check for escaping stack data?


But I'm not sure that you're right, this looks broken to me, even
without @safe.

What does it mean to create immutable data on the stack? The stack is
intrinsically mutable!


So is the heap.


No it is not. Data on the stack *cannot* survive past the end of the 
function call. Data on the heap can last forever.



What does it mean to garbage collect immutable data?


From the point of view of the application, it doesn't happen. There are 
no observable semantics. It's merely an implementation detail.



What does it mean to allocate an 'int' on the stack?


What does it mean to delete immutable data?


Deallocate the storage for it and make it available for reuse.
Accessing it afterwards leads to arbitrary behaviour. This is the same
with mutable data. As the program may behave arbitrarily in this case,
it is valid behaviour to act as if immutable data changed.


No, you've broken the type system if you've deleted immutable data.
If I have a reference to an immutable variable, I have a guarantee that 
it will never change. delete will break that guarantee.


With a mutable variable, I have no such guarantee. (It's not safe to 
allocate something different in the deleted location, but it's OK to run 
the finalizer and then wipe all the memory).



I think it's reasonable for both of them to require a cast, even in
@system code.



The implementation of the 'scope' storage class should be fixed. We
could then require an unsafe cast(scope) to disable prevention of stack
address escaping.


No we can't. f cannot know that the string it has been given is on the 
stack. So main() must prevent it from being given to f() in the first 
place. How can it do that?


void foo(bool b, string y)
{
  immutable (char)[4] x = abba;
  string s = b ? x : y;
  f(s);
}

Make it safe.



Rust's borrowed pointers may give some hints on how
to extend 'scope' to fields of structs.


I think it is more fundamental than that.


As to delete, delete is as unsafe when the involved data is immutable
as when it is mutable. Why require an additional cast in one case?


This is not about safety.
Modifying immutable data breaks the type system. Deleting mutable data 
does not. AFAIK it is safe to implement delete as a call to the 
finalizer, followed by setting the memory to T.init. Only the GC can 
determine if it is safe to reuse the memory.


Deleting immutable data just doesn't make sense.


Re: Bits rotations

2012-10-18 Thread Don Clugston

On 18/10/12 11:39, Iain Buclaw wrote:

On 18 October 2012 09:27, bearophile bearophileh...@lycos.com wrote:

Iain Buclaw:



In the gdc-4.6 package you have there, it's only naked asm that can't be
inlined.



Good.




However it is worth noting that DIASM is no longer in mainline gdc.



What's DIASM? Is it the D syntax for asm code? If this is right, then gdc
developers have done a mistake, reducing D code interoperability, creating
an incompatibility where there wasn't (and reducing my desire to use gdc or
to switch to it, because I have hundreds of lines of inlined asm in my D
code), this means doing the opposite of what generally compiler writers are
supposed to do (maybe this topic was discussed already, in past).

Bye,
bearophile



This topic has been discussed in the past.  And the current status is
that GCC mainline has poisoned the frontend to use certain headers
that the IASM implementation in GDC depended on.

Example:

int zz(int p1)
{
   asm {
 naked;
 mov EAX, p1[EBP];
   }
}


To calculate p1[EBP], one would have to know where p1 will land on the
frame pointer to replace it with the relavant offset value.  This
would mean from the front-end we would have to invoke the back-end to
generate and tell us the stack frame layout of zz, which is not
possible because:


FYI: That code doesn't work in DMD either.
DMD assumes a frame pointer is created in naked ASM, which is totally 
wrong. Code like that should not compile. The compiler does not know 
what the correct offsets are and should not attempt to try.



a) Invoking this before the optimisation passes may produce a
different result to what that actual result is after the optimisation
passes.
b) All functions are sitting in poisoned (for the front-end) headers.

There is an opportunity to defer parsing IASM until the GIMPLE
(middle-end) stage, however am still unable to retrieve the required
information to produce the correct codegen.


Are you just talking about naked asm? Conceptually naked asm should act 
as if it was created in an assembler in a seperate obj file, and 
accessed via extern(C).

If you have problems with non-naked asm, that would make more sense to me.



Re: Regarding hex strings

2012-10-18 Thread Don Clugston

On 18/10/12 10:58, foobar wrote:

On Thursday, 18 October 2012 at 02:47:42 UTC, H. S. Teoh wrote:

On Thu, Oct 18, 2012 at 02:45:10AM +0200, bearophile wrote:
[...]

hex strings are useful, but I think they were invented in D1 when
strings were convertible to char[]. But today they are an array of
immutable UFT-8, so I think this default type is not so useful:

void main() {
string data1 = xA1 B2 C3 D4; // OK
immutable(ubyte)[] data2 = xA1 B2 C3 D4; // error
}


test.d(3): Error: cannot implicitly convert expression
(\xa1\xb2\xc3\xd4) of type string to ubyte[]

[...]

Yeah I think hex strings would be better as ubyte[] by default.

More generally, though, I think *both* of the above lines should be
equally accepted.  If you write xA1 B2 C3 in the context of
initializing a string, then the compiler should infer the type of the
literal as string, and if the same literal occurs in the context of,
say, passing a ubyte[], then its type should be inferred as ubyte[], NOT
string.


T


IMO, this is a redundant feature that complicates the language for no
benefit and should be deprecated.
strings already have an escape sequence for specifying code-points \u
and for ubyte arrays you can simply use:
immutable(ubyte)[] data2 = [0xA1 0xB2 0xC3 0xD4];

So basically this feature gains us nothing.


That is not the same. Array literals are not the same as string 
literals, they have an implicit .dup.
See my recent thread on this issue (which unfortunately seems have to 
died without a resolution, people got hung up about trailing null 
characters without apparently noticing the more important issue of the dup).




Re: How mutable is immutable?

2012-10-17 Thread Don Clugston

On 01/01/12 13:50, Timon Gehr wrote:

On 01/01/2012 10:40 AM, Denis Shelomovskij wrote:

So, I'm a function `f`, I have an `immutable(type)[]` argument and I
want to store it for my friend `g` in an TLS variable `v`:
---
string v;
debug string sure;

void f(string s) { v = s; debug sure = s.idup; }
void g() { assert(v == sure); }
---
I also store a copy of `s` into `sure` for my friend to ensure immutable
date hasn't been mutated.
Can my friend's assertion ever fail without breaking a type-system?
Sure. Just consider this:
---
void main() {
auto s = abba.idup;
f(s);
delete s;
g();
}
---
Is it by-design? Looks like deleting immutable (and const because of
implicit conversion) data should be prohibited.
OK. Let `delete` be fixed. Can we still fail?
---
void h() {
immutable(char)[4] s = abba;
f(s);
}
void main() {
h();
g();
}
---
Damn! So, what can we do with it? Not sure, but I have a proposal.

Fix it in language:
* disallow `delete` of const/immutable data
* disallow immutable data on the stack

This makes data really immutable if I don't miss something. Anyway, I
want `immutable` qualified data to be immutable without breaking a
type-system (if one do it, its his own responsibility), so some changes
should be made (IMHO).


You are using unsafe language features to break the type system. That is
not the fault of the type system.

'@safe:' at the top of the program should stop both examples from
working, it is a bug that it does not.


That's the point -- *which* checks are missing from @safe?
But I'm not sure that you're right, this looks broken to me, even 
without @safe.


What does it mean to create immutable data on the stack? The stack is 
intrinsically mutable!

What does it mean to delete immutable data?
I think it's reasonable for both of them to require a cast, even in 
@system code.





Re: alias A = B; syntax

2012-10-16 Thread Don Clugston

On 16/10/12 05:18, Nick Sabalausky wrote:

On Tue, 16 Oct 2012 05:00:56 +0200
stas stas...@yahoo.com wrote:


For me syntax alias int Int; seems unnatural.
I'd love to write
alias Int = int;
alias fptr = void(int)*;

This looks much more readable for me and harmonized with
int x = 0;
template T(alias A = Object) {...}

Does anybody share this opinion?
Any chance this syntax goes into D someday?


I'm pretty sure it was already decided that this would be added, but
just hasn't made it in yet. I've been fairly eager for it. I find the
current syntax too inconsistent and confusing.



That's my recollection too. I find that even after using it for years, I 
still have to pause and think for a moment whenever I see an alias:


alias Foo Bar;
// is this declaring Foo as an alias of Bar? Or Bar as an alias of Foo?
And if I see:
alias Foo int;
it doesn't instantly stand out to me as the wrong way round. There's a 
delay of 1-2 seconds.


Somehow this is something that my brain refuses to see as natural, no 
matter how many times it sees it. Whereas:


alias Bar = Foo;

is instantly clear, even though I've almost never seen it.



Re: D seems interesting, but...

2012-10-15 Thread Don Clugston

On 15/10/12 06:42, Jonathan M Davis wrote:

On Sunday, October 14, 2012 21:39:42 H. S. Teoh wrote:

This looks like what happens if you try to use the latest dmd release
with an old version of Phobos, perhaps installed along with gdc.

Whoever's doing the .deb packaging really should add a versioned
Depends: field to debian/control so that it will require installation of
the correct version of Phobos, or, at the very least, refuse to install
if such is not available.


At this point, it's a bad idea to use any version of druntime or Phobos which
doesn't match exactly with the version of dmd that you're using. It's not as
bad as it used to be, but there are still plenty of cases where a language
change (be it a bug fix or added feature or whatever) makes it so that older
versions of Phobos won't compile, or the latest Phobos ends up needing the
latest dmd. I wouldn't advise anyone to use versions of them that don't all
match.

- Jonathan M Davis



I think we should have a version number in druntime which is checked by 
the compiler, and bumped every time an incompatible change is made. That 
way we could reduce the number of messages from frustrated and

bewildered users.


Re: D seems interesting, but...

2012-10-15 Thread Don Clugston

On 15/10/12 11:14, Jacob Carlborg wrote:

Just use DVM, it's also cross-platform:

https://bitbucket.org/doob/dvm


I tried that on both Windows and Ubuntu, and couldn't get it to work on 
either of them. I posted a couple of bug reports eight months ago, and 
they still haven't been fixed. Not recommended for anyone who is having 
problems with their installation.


Re: Why are scope variables being deprecated?

2012-10-11 Thread Don Clugston

On 11/10/12 02:30, Piotr Szturmaj wrote:

Jonathan M Davis wrote:

On Thursday, October 11, 2012 01:24:40 Piotr Szturmaj wrote:

Could you give me an example of preventing closure allocation? I think I
knew one but I don't remember now...


Any time that a delegate parameter is marked as scope, the compiler
will skip
allocating a closure. Otherwise, it has to copy the stack from the
caller onto
the heap to create a closure so that the delegate will continue to
work once
the caller has completed (e.g. if the delegate were saved for a
callback and
then called way later in the program). Otherwise, it would refer to an
invalid
stack and really nasty things would happen when the delegate was
called later.

 

By marking the delegate as scope, you're telling the compiler that it
will not
escape the function that it's being passed to, so the compiler then
knows that
the stack that it refers to will be valid for the duration of that
delegate's
existence, so it knows that a closure is not required, so it doesn't
allocate
it, gaining you efficiency.


Thanks, that's clear now, but I found a bug:

__gshared void delegate() global;

void dgtest(scope void delegate() dg)
{
 global = dg; // compiles
}

void dguse()
{
 int i;
 dgtest({ writeln(i++); });
}

I guess it's a known one.


Looks like bug 5270?





Re: next_permutation and cartesian product for ranges?

2012-10-10 Thread Don Clugston

On 10/10/12 00:22, bearophile wrote:

Steven Schveighoffer:


Is there any advantage over having a function?  I'd think you could
easily build a range based on the function, no?


Generators (that yield lexicographic permutations, permutation swaps,
combinations, etc) are quite more handy, you can compose them with the
other ranges and higher order functions.



Adding to Phobos few ranges that build on a next_permutation(),
next_combination(), etc, is possible, but I don't see a big need for
such C++-style functions, the ranges are enough.


What makes you think that permutations are only ever used in a range 
context? Do you have any evidence for that?


Sounds like an abstraction inversion to me.




Re: What is the case against a struct post-blit default constructor?

2012-10-10 Thread Don Clugston

On 10/10/12 11:21, Jonathan M Davis wrote:

On Monday, October 08, 2012 18:47:43 Malte Skarupke wrote:

So I really can't think of a reason for why you wouldn't want
this. Yet this discussion has happened several times already.
There is clear demand for it and very good reasons, such as those
mentioned in all the linked discussions.

So why is this being rejected?


It buys you pretty much nothing. There are plenty of places in the language
where init is required (e.g. member variables that can't be directly
initialized and the elements in an array). So, init _will_ be used regardless
of what you do with the default constructor. If you want to prevent that, then
you need to disable init, which we can already do. But you're not going to get
those things initialized with the default constructor, which kind of defeats
the purpose of the default constructor. If you can't guarantee that every
instance which isn't explicitly constructed is default constructed, then
what's the point?


Of course there would be no point.
You have not answered the question. The issue is, WHY can we not 
guarantee that that the struct default constructor is called?


I have a vague memory that Walter mentioned a technical difficulty once 
but I don't remember anything about what it was.


I can't imagine what it would be. Even in the worst case, it would be 
possible to run CTFE on the default constructor in order to create 
.init. This would limit the default constructor to things which are 
CTFEable, but even that would still be useful for templated structs.


Really, there does not seem to me to be any point in having an invariant 
for a struct, without a default constructor.


BTW .init doesn't really work for nested structs anyway. There are 
several open bugs related to that.




Re: What is the case against a struct post-blit default constructor?

2012-10-10 Thread Don Clugston

On 10/10/12 13:27, Timon Gehr wrote:

On 10/10/2012 12:45 PM, Don Clugston wrote:

On 10/10/12 11:21, Jonathan M Davis wrote:

On Monday, October 08, 2012 18:47:43 Malte Skarupke wrote:

So I really can't think of a reason for why you wouldn't want
this. Yet this discussion has happened several times already.
There is clear demand for it and very good reasons, such as those
mentioned in all the linked discussions.

So why is this being rejected?


It buys you pretty much nothing. There are plenty of places in the
language
where init is required (e.g. member variables that can't be directly
initialized and the elements in an array). So, init _will_ be used
regardless
of what you do with the default constructor. If you want to prevent
that, then
you need to disable init, which we can already do. But you're not
going to get
those things initialized with the default constructor, which kind of
defeats
the purpose of the default constructor. If you can't guarantee that
every
instance which isn't explicitly constructed is default constructed, then
what's the point?


Of course there would be no point.
You have not answered the question. The issue is, WHY can we not
guarantee that that the struct default constructor is called?



Because the current language does not. :o)

Because that would imply disabling .init.
  - Which defeats the .init idiom in generic code. I am not convinced
that we need that though.


I don't like the .init idiom, I'm not sure it actually works. The 
semantics of .init aren't well defined. There is no guarantee that it is 
a valid value of the type.



 (T x)=... does the job just fine, and

.init has issues, as eg. int.init has special implicit conversion
rules that not all members of the type int share.
  - Need a new (unsafe) language feature in order to be able to
implement eg. 'emplace'.


Exactly.



I have a vague memory that Walter mentioned a technical difficulty once
but I don't remember anything about what it was.

I can't imagine what it would be.


+1.


Even in the worst case, it would be
possible to run CTFE on the default constructor in order to create
.init. This would limit the default constructor to things which are
CTFEable, but even that would still be useful for templated structs.



You could run CTFE on the default constructor iff .init is requested,
but I don't really see the point. What would be the benefit?


You could have more complicated relationships between members.

struct W
{
  int x;
  int y;
}

W bar(T)() { return W(T.sizeof, T.alignof); }

struct Foo(T)
{
   int m;
   int n;
   int k;

   this() {
 W w = bar!(T)();
 m = w.x;
 n = w.y;
 k = abs(64 - m - n);
   }
}

of course it gains in value as bar!()() gets more complicated.



Really, there does not seem to me to be any point in having an invariant
for a struct, without a default constructor.



One can use a dented invariant.

struct S{
 bool valid = false;
 // ...
 invariant(){ if(valid) assert(...); }
 void establishInvariant()out{assert(valid);}body{...}
}


Yes, you have to do something like that. It's absolute garbage. When you 
have a hack like that, I don't see the point of having invariants in the 
language.




BTW .init doesn't really work for nested structs anyway. There are
several open bugs related to that.



That is true, what are the plans for that?


Don't know.


Re: Error messages for newbies survey

2012-10-10 Thread Don Clugston

On 10/10/12 14:09, bearophile wrote:

  From Reddit, a nice survey:
http://www.reddit.com/r/coding/comments/118ssp/honours_student_at_my_university_is_doing_a/




For my Computer Science Honours research project, I am currently
investigating ways of improving the terse, technical error messages
given by traditional compilers to make them more useful to novice
programmers. As part of this research, I have designed this survey to
help determine which types of common novice errors are inadequately
reported by a traditional compiler and to gather ideas on how they
should be reported to a novice.


http://www.esurveyspro.com/Survey.aspx?id=23752434-e25f-4a48-86bf-bb2634e1b5ce


So this survey is not to improve error messages in general, it's
specific for newbies. So the error situations shown in the survey
are not typical for C programmers.

Below some of the examples converted to D, with their relative
error messages.


Many of the things you report are examples of bug 8684. Please file bug 
reports for any others you think are important.


Re: Best way of passing in a big struct to a function?

2012-10-10 Thread Don Clugston

On 10/10/12 09:12, thedeemon wrote:

On Wednesday, 10 October 2012 at 07:28:55 UTC, Jonathan M Davis wrote:

Making sure that the aa has been properly initialized before passing
it to a function (which would mean giving it at least one value) would
make the ref completely unnecessary.

- Jonathan M Davis


Ah, thanks a lot! This behavior of a fresh AA being null and then
silently converted to a non-null when being filled confused me.


Yes, it's confusing and annoying.
This is something in the language that we keep talking about fixing, but 
to date it hasn't happened.


Re: D 1.076 Alpha for Windows 64 bits, works with VS 2010

2012-10-09 Thread Don Clugston

On 06/10/12 20:38, Walter Bright wrote:

On 9/30/2012 9:35 PM, Andrej Mitrovic wrote:

On 10/1/12, Walter Bright newshou...@digitalmars.com wrote:

Also, consider that in C++ you can throw any type, such as an int. There
is no credible way to make this work reasonably in D, as exceptions are
all derived from Exception.


Is that a bug or a feature? :)



It's a feature, and I'm not joking.

What is the compelling use case for throwing an int? How could that
possibly fit into some encapsulation model? What if library A throws an
int, and library B does? Now you catch an int - which did it come from?
You've got no clue. It's indistinguishable from garbage.



Just imagine how much fun could be had, if D let you throw sqrt(17.0) + 
37.919i.






Re: Feature request: extending comma operator's functionality

2012-10-08 Thread Don Clugston

On 05/10/12 18:58, H. S. Teoh wrote:

On Fri, Oct 05, 2012 at 05:23:40PM +0200, Don Clugston wrote:
[...]

My feeling is that  do{}while() is a fairly useless concept, and
this is part of the reason.
In my experience genuine do-while loops are extremely rare, and it
only takes a slight change to the loop to force a different
structure to be used.
Conditional loops which don't follow the while(){...} pattern
normally follow the loop-and-a-half pattern, also known as
begin-while-repeat (I think that's the name Knuth used). I'll call
it 'super do':

super do {
foo();
while(cond);
bar();
}

which in D is better modelled by:

for (;;)
{
foo();
if (!cond) break;
bar();
}


This isn't super do, it's just loop, the way nature intended. ;-)
I've always been an advocate of this construct:

loop {
// initial part of loop body
} while(cond) { // exit point
// trailing part of loop body
}



Looks OK, except that the scopes look wrong. I would hope than a 
variable declared in the initial part of the body is also visible in the 
trailing part. The {} don't work properly.
Regardless of the syntax, I think it is _the_ fundamental loop 
construct, and I've always found it odd that most languages don't 
include it. I first found encountered it in Forth, and have missed it 
ever since.



To some extent, D (and C/C++)'s for-loops exhibit a similar structure:

for (X; Y; Z) {}

The trailing part of the loop body corresponds with Z; the condition
corresponds with Y.


Yes. C got 'for' loops right.


To avoid the introduction of a new keyword, we may fuse the do-loop and
the while-loop together:

do {
...
} while (cond) {
...
}

The current do-loop is simply a special case of this construct where the
second {...} is replaced with a ;, and the while-loop is a special case
of this construct where the initial part of the loop is elided.

I argue that this generalized construct is much more useful than the
do-loop or while-loop individually, plus it doesn't break any existing
code.


I agree that it's more useful. But that code was legal until a couple of 
releases ago, because a trailing ; was not required on do-while loops.


do { xxx; } while(cond) { yyy; }

means:
do {
  xxx;
}
while(cond);
yyy;

Even without that, it puts a huge significance on that semicolon. So I 
don't think that works. How about:


do {  ...  do while (cond);  ... }

?
This is technically already legal too, although 'do while(cond);' is 
currently either a no-op, or an infinite loop.




Re: Feature request: extending comma operator's functionality

2012-10-05 Thread Don Clugston

On 05/10/12 15:35, monarch_dodra wrote:

On Friday, 5 October 2012 at 00:22:04 UTC, Jonathan M Davis wrote:

On Friday, October 05, 2012 02:08:14 bearophile wrote:

[SNIP]
Regarding definition of variables in D language constructs, there
is one situation where sometimes I find D not handy. This code
can't work:

do {
const x = ...;
} while (predicate(x));


You need to use:

T x;
do {
x = ...;
} while (predicate(x));


Yeah. That comes from C/C++ (and is the same in Java and C#, I
believe). I
don't know why it works that way. It's definitely annoying.

[SNIP]

- Jonathan M Davis


Because it's the only way to guarantee that x exits when you reach the
end of the loop.

do {
   if(true) continue; //Yawn... skip.
   const x = ... ;
} while (predicate(x)); //What's x?

Basic goto limitations. Unlike goto though, inserting a continue
should never create a compile error, so the compiler *has* to guarantee
that the if condition references nothing inside its own block.

It is annoying, but nothing that can't be fixed with a scope bloc.


My feeling is that  do{}while() is a fairly useless concept, and this is 
part of the reason.
In my experience genuine do-while loops are extremely rare, and it only 
takes a slight change to the loop to force a different structure to be used.
Conditional loops which don't follow the while(){...} pattern normally 
follow the loop-and-a-half pattern, also known as begin-while-repeat (I 
think that's the name Knuth used). I'll call it 'super do':


super do {
   foo();
   while(cond);
   bar();
}

which in D is better modelled by:

for (;;)
{
   foo();
   if (!cond) break;
   bar();
}

rather than by a do-while loop. But it's a bit ugly, and doesn't enforce 
a single break. IMHO it's a shame we've gone with the fairly useless 
do-while, rather than cleaning up the syntax for loop-and-a-half.


I don't think the proposed changes bring us much closer to a useful 
language construct.


Re: Proposal: clean up semantics of array literals vs string literals

2012-10-04 Thread Don Clugston

On 02/10/12 17:14, Andrei Alexandrescu wrote:

On 10/2/12 7:11 AM, Don Clugston wrote:

The problem
---

String literals in D are a little bit magical; they have a trailing \0.

[snip]

I don't mean to be Debbie Downer on this because I reckon it addresses
an issue that some have, although I never do. With that warning, a few
candid opinions follow.

First, I think zero-terminated strings shouldn't be needed frequently
enough in D code to make this necessary.


[snip]

You're missing the point, a bit. The zero-terminator is only one symptom 
of the underlying problem: string literals and array literals have the 
same type but different semantics.

The other symptoms are:
* the implicit .dup that happens with array literals, but not string 
literals.
This is a silent performance killer. It's probably the most common 
performance bug we find in our code, and it's completely ungreppable.


* string literals are polysemous with width (c, w, d) but array literals 
are not (they are polysemous with constness).

For example,
abc ~ 'ü'
is legal, but
['a', 'b', 'c'] ~ 'ü'
is not.
This has nothing to do with the zero terminator.



Re: It seems pure ain't so pure after all

2012-10-02 Thread Don Clugston

On 01/10/12 07:40, Tommi wrote:

import std.stdio;

int pow2(int val) pure
{
 if (__ctfe)
 return 6;
 else
 return val * val;
}

void main()
{
assert(pow2(3) == 9);
 static assert(pow2(3) == 6);

 writeln(9 = 6 ... I knew it! '6' was faking it all along);
 readln();
}


You don't need the if (__ctfe) to show this behaviour. Nor do you even 
need CTFE at all (though it would be a bit less obvious). You could 
demonstrate it in C++ too.


Any code that behaves differently when compiled with -O, will do this as 
well. Constant folding of floating point numbers does the same thing, if 
the numbers are represented in the compiler in a different precision to 
how the machine calculates them. I believe that GCC, for example, uses 
very much higher precision (hundreds of bits) at compile time.








Proposal: clean up semantics of array literals vs string literals

2012-10-02 Thread Don Clugston

The problem
---

String literals in D are a little bit magical; they have a trailing \0. 
This means that is possible to write,


printf(Hello, World!\n);

without including a trailing \0. This is important for compatibility 
with C. This trailing \0 is mentioned in the spec but only incidentally, 
and generally in connection with printf.


But the semantics are not well defined.

printf(Hello, W ~ orld!\n);

Does this have a trailing \0 ? I think it should, because it improves 
readability of string literals that are longer than one line. Currently 
DMD adds a \0, but it is not in the spec.


Now consider array literals.

printf(['H','e', 'l', 'l','o','\n']);

Does this have a trailing \0 ? Currently DMD does not put one in.
How about ['H','e', 'l', 'l','o'] ~  World!\n  ?

And Hello  ~ ['W','o','r','l','d','\n']   ?

And Hello World! ~ '\n' ?
And  null ~ Hello World!\n ?

Currently DMD puts \0 in some cases but not others, and it's rather random.

The root cause is that this trailing zero is not part of the type, it's 
part of the literal. There are no rules for how literals are propagated 
inside expressions, they are just literals. This is a mess.


There is a second difference.
Array literals of char type, have completely different semantics from 
string literals. In module scope:


char[] x = ['a'];  // OK -- array literals can have an implicit .dup
char[] y = b;// illegal

This is a big problem for CTFE, because for CTFE, a string is just a 
compile-time value, it's neither string literal nor array literal!


See bug 8660 for further details of the problems this causes.


A proposal to clean up this mess


Any compile-time value of type immutable(char)[] or const(char)[], 
behaves a string literals currently do, and will have a \0 appended when 
it is stored in the executable.


ie,

enum hello = ['H', 'e', 'l', 'l', 'o', '\n'];
printf(hello);

will work.

Any value of type char[], which is generated at compile time, will not 
have the trailing \0, and it will do an implicit dup (as current array 
literals do).


char [] foo()
{
return abc;
}

char [] x = foo();

// x does not have a trailing \0, and it is implicitly duped, even 
though it was not declared with an array literal.


---
So that the difference between string literals and char array literals 
would simply be that the latter are polysemous. There would be no 
semantics associated with the form of the literal itself.



We still have this oddity:


void foo(char qqq = 'b') {

   string x = abc;// trailing \0
   string y = ['a', 'b', 'c'];  // trailing \0
   string z = ['a', qqq, 'c'];  // no trailing \0
}

This is because we made the (IMHO mistaken) decision to allow variables 
inside array literals.
This is the reason why I listed _compile time value_ in the requirement 
for having a \0, rather than entirely basing it on the type.


We could fix that with a language change: an array literal which 
contains a variable should not be of immutable type. It should be of 
mutable type (or const, in the case where it contains other, immutable 
values).


So char [] w = ['a', qqq, 'c']; should compile (it currently doesn't, 
even though w is allocated on the heap).


But that's a separate proposal from the one I'm making here. I just need 
a decision on the main proposal so that I can fix a pile of CTFE bugs.


Re: Proposal: clean up semantics of array literals vs string literals

2012-10-02 Thread Don Clugston

On 02/10/12 14:02, Andrej Mitrovic wrote:

On 10/2/12, Don Clugston d...@nospam.com wrote:

A proposal to clean up this mess


Any compile-time value of type immutable(char)[] or const(char)[],
behaves a string literals currently do, and will have a \0 appended when
it is stored in the executable.

ie,

enum hello = ['H', 'e', 'l', 'l', 'o', '\n'];
printf(hello);

will work.


What about these, will these pass?:

enum string x = foo;
assert(x.length == 3);

void test(string x) { assert(x.length == 3); }
test(x);

If these don't pass the proposal will break code.


Yes, they pass. The \0 is not included in the string length. It's 
effectively in the data segment, not in the string.





Re: Proposal: clean up semantics of array literals vs string literals

2012-10-02 Thread Don Clugston

On 02/10/12 13:26, deadalnix wrote:

Well the whole mess come from the fact that D conflate C string and D
string.

The first problem come from the fact that D array are implicitly
convertible to pointer. So calling D function that expect a char* is
possible with D string even if it is unsafe and will not work in the
general case.

The fact that D provide tricks that will make it work in special cases
is armful as previous discussion have shown (many D programmer assume
that this will always work because of toy tests they have made, where in
case it won't and toStringz must be used).

The only sane solution I can think of is to :
  - disallow slice to convert implicitly to pointer. .ptr is made for that.
  - Do not put any trailing 0 in string literal, unless it is specified
explicitly ( foobar\0 ).
  - Except if a const(char)* is expected from the string literal. In
case it becomes a Cstring literal, with a trailing 0. This is made to
allow uses like printf(foobar);

In other terms, the receiver type is used to decide if the compiler
generate a string literal or a Cstring literal.


This still doesn't solve the problem of the difference between array 
literals and string literals (the magical implicit .dup), which is the 
key problem I'm trying to solve.




Re: Proposal: clean up semantics of array literals vs string literals

2012-10-02 Thread Don Clugston

On 02/10/12 13:18, Tobias Pankrath wrote:

On Tuesday, 2 October 2012 at 11:10:46 UTC, Don Clugston wrote:

The problem
---

String literals in D are a little bit magical; they have a trailing
\0. This means that is possible to write,

printf(Hello, World!\n);

without including a trailing \0. This is important for compatibility
with C. This trailing \0 is mentioned in the spec but only
incidentally, and generally in connection with printf.

But the semantics are not well defined.

printf(Hello, W ~ orld!\n);


If every string literal is \0-terminated, then there should be two \0 in
the final string. I guess that's not the case and that's actually my
preferred behaviour, but the spec should make it crystal clear in which
situations a
string literal gets a terminator and in which not.


The \0 is *not* part of the string, it lies after the string.
It's as if all memory is cleared, then the string literals are copied 
into it, with a gap of at least one byte between each. The 'trailing 0' 
is not part of the literal, it's the underlying cleared memory.


At least, that's how I understand it. The spec is very vague.



Re: Is it possible to force CTFE?

2012-10-01 Thread Don Clugston

On 27/09/12 15:01, bearophile wrote:

Tommi:


2) Is it possible to specialize a function based on whether or not the
parameter that was passed in is a compile time constant?


I am interested in this since some years. I think it's useful, but I
don't know if it can be implemented. I don't remember people discussing
about this much.

Bye,
bearophile


It has been discussed very often, especially around the time that CTFE 
was first introduced. We never came up with a solution.




Re: About std.ascii.toLower

2012-09-27 Thread Don Clugston

On 20/09/12 18:57, Jonathan M Davis wrote:

On Thursday, September 20, 2012 18:35:21 bearophile wrote:

monarch_dodra:

It's not, it only *operates* on ASCII, but non ascii is still a



legal arg:

Then maybe std.ascii.toLower needs a pre-condition that
constraints it to just ASCII inputs, so it's free to return a
char.


Goodness no.

1. Operating on a char is almost always the wrong thing to do. If you really
want to do that, then cast. It should _not_ be encouraged.

2. It would be disastrous if std.ascii's funtions didn't work on unicode.
Right now, you can use them with ranges on strings which are unicode, which
can be very useful.

 I grant you that that's more obvious with something like

isDigit than toLower, but regardless, std.ascii is designed such that its
functions will all operate on unicode strings. It just doesn't alter unicode
characters and returns false for them with any of the query functions.


Are there any use cases of toLower() on non-ASCII strings?
Seriously? I think it's _always_ a bug.

At the very least that function should have a name like 
toLowerIgnoringNonAscii() to indicate that it is performing a really, 
really foul operation.


The fact that toLower(Ü) doesn't generate an error, but doesn't return 
ü is a wrong-code bug IMHO. It isn't any better than if it returned a 
random garbage character (eg, it's OK in my opinion for ASCII toLower to 
consider only the lower 7 bits).


OTOH I can see some value in a cased ASCII vs unicode comparison.
ie, given an ASCII string and a unicode string, do a case-insensitive 
comparison, eg look for

HTML inside öähaøſ€đ@htmlſŋħŋ€ł¶



Re: Should this be flagged as a warning?

2012-09-26 Thread Don Clugston

On 25/09/12 21:30, Bernard Helyer wrote:

I tried to post this last night, but the NG wasn't having any of it.

I found myself writing a bug that looked like this

 match(ts, TokenType.Is);
 match(ts, TokenType.OpenParen);
 isExp.type == parseType(ts);

The bug being of course, that a type is parsed and ts is modified,
so the expression has side effects so it's not flagged as a useless
expression. But the comparison still has no effect, so should this be
flagged by DMD?

-Bernard.



The must have an effect rule only applies to statements, not 
expressions, so this is according to the spec. It's not a bug.


This is a bit like the more extreme case I recently posted about:

int x, y, z;
x == y, ++z;

doesn't generate an error message even though x == y has no 
side-effects, because comma is an expression, not a statement.


IMHO, every expression should be required to have an effect. For example
foo() + foo();
shouldn't compile, unless + is an overloaded operator with side-effects.

It would be really interesting to add this check, and then compile 
existing code (such as Phobos) to see if it breaks valid code, or 
reveals bugs.





Re: Order of evaluation - aka hidden undefined behaviours.

2012-09-26 Thread Don Clugston

On 26/09/12 01:31, H. S. Teoh wrote:

On Wed, Sep 26, 2012 at 01:10:00AM +0200, Timon Gehr wrote:

On 09/26/2012 12:58 AM, Iain Buclaw wrote:

[...]

string abc;

float[] A()
{
 abc ~= A;
 return [];
}

float[] B()
{
 abc ~= B;
 return [];
}

float[] C()
{
 abc ~= C;
 return [];
}

void main()
{
 A()[] = B()[] + C()[];
 assert(abc == ???);
}


Without cheating, I invite people to have a good guess what 'abc' is
equal to, but just to narrow it down.

1)  It isn't ABC.
2)  On x86/x86_64, it isn't ACB.
3)  On everything else, it's the reverse of what you'd expect on
x86/x86_64.

The problem here is that the array operation A[] = B[] + C[] gets
transformed into an extern(C) call.  And because there's no strict rules
in place over the order of which it's parameters are evaluated, it could
go either way (LTR, or RTL).

Serious note: This test is bogus as this and similar other failing tests
on non-x86 platforms are not at all obvious to the users who get issues.
So what are we to do about it?

[...]

As far as my understanding of the issue goes, the correct answer is
ABC, and compilers that do not produce ABC are buggy.

The solution is to transform the code to code that evaluates the
arguments to the extern(C) call in the correct order and eg. stores
them in temporaries before passing them on.

[...]

Shouldn't it be BCA? I'd expect the assignment operation to take place
last, so the corresponding expression should be evaluated last.


I expected BCA too. Left associative expressions evaluated 
left-to-right, right associative expressions evaluated right-to-left.




Re: Should this be flagged as a warning?

2012-09-26 Thread Don Clugston

On 26/09/12 14:19, Timon Gehr wrote:

On 09/26/2012 11:45 AM, Don Clugston wrote:

On 25/09/12 21:30, Bernard Helyer wrote:

I tried to post this last night, but the NG wasn't having any of it.

I found myself writing a bug that looked like this

 match(ts, TokenType.Is);
 match(ts, TokenType.OpenParen);
 isExp.type == parseType(ts);

The bug being of course, that a type is parsed and ts is modified,
so the expression has side effects so it's not flagged as a useless
expression. But the comparison still has no effect, so should this be
flagged by DMD?

-Bernard.



The must have an effect rule only applies to statements, not
expressions, so this is according to the spec. It's not a bug.

This is a bit like the more extreme case I recently posted about:

int x, y, z;
x == y, ++z;

doesn't generate an error message even though x == y has no
side-effects, because comma is an expression, not a statement.

IMHO, every expression should be required to have an effect.


I'd rather restrict this to expressions whose value is unused.


If the value is used, it has an effect.


Otherwise 'a = b is c;' will be illegal, because 'b is c' does not have
an effect.


For example foo() + foo();
shouldn't compile, unless + is an overloaded operator


Yes.


with side-effects.



Not sure about that. In generic code, it is possible and likely (as pure
is inferred for lambdas and template functions) that a pure
function ends up being called for potential side effects.


I wouldn't give it special treatment. I think it should be allowed if 
and only if


plus(foo(), foo());

compiles, when plus is pure nothrow.


Re: std.math.frexp wrong on ARM

2012-09-26 Thread Don Clugston

On 26/09/12 17:13, Johannes Pfau wrote:

The frexp test fails on ARM. I think the mask in line 1491 is
wrong:

https://github.com/D-Programming-Language/phobos/blob/master/std/math.d#L1491
For doubles, the 63 bit is sign, 62-52 are exponent and 51-0 are
mantissa.
The mask manipulates the bits 63-48 (ushort, 16bit)
0x8000 is 0b1000
so it preserves the sign, but not the 4 bits of the mantissa? I think
it should be
0b1000 (0x800F)?
This also fixes the test case on ARM.

But I don't know much about this stuff, so I wonder if this is correct?


You are correct. I will fix.

At least, it's good that the tests caught that.


Re: function is not function

2012-09-26 Thread Don Clugston

On 21/09/12 21:59, Ellery Newcomer wrote:

solution is to use std.traits, but can someone explain this to me?

import std.stdio;

void main() {
 auto a = {
 writeln(hi);
 };
 pragma(msg, typeof(a)); // void function()
 pragma(msg, is(typeof(a) == delegate)); // nope!
 pragma(msg, is(typeof(a) == function)); // nope!
}



The 'function' keyword is an ugly wart in the language.  In

void function()

'function' means 'function pointer'. But in

is (X == function)

'function' means 'function'.

Which is actually pretty much useless. You always want 'function 
pointer'. This is the only case where function type still exists in 
the language.





Re: object.error: Privileged Instruction

2012-09-26 Thread Don Clugston

On 22/09/12 21:49, Jonathan M Davis wrote:

On Saturday, September 22, 2012 21:19:27 Maxim Fomin wrote:

Privilege instruction is an assembly instruction which can be
executed only at a certain executive process context, typically
os kernel. AFAIK assert(false) was claimed to be implemented by
dmd as a halt instruction, which is privileged one.

However, compiled code shows that dmd generates int 3 instruction
for assert(false) statement and 61_6F_65_75 which is binary
representation of aoeu for assert(false, aoeu) statement and
the latter is interpreted as privileged i/o instruction.


It's a normal assertion without -release. With -release, it's a halt
instruction on Linux but IIRC it's something slightly different (albeit
similar) on Windows, though it might be halt there too.

- Jonathan M Davis



I implemented the code runtime code that does it, at least on Windows. 
You get much better diagnostics on Windows.
IMHO it is a Linux misfeature, they conflate a couple of unrelated 
hardware exceptions together into one signal, making it hard to identify 
which it was.




Re: DIP19: Remove comma operator from D and provision better syntactic support for tuples

2012-09-25 Thread Don Clugston

On 24/09/12 17:19, Andrei Alexandrescu wrote:

On 9/24/12 4:17 AM, Don Clugston wrote:

Regarding the comma operator: I'd love to deprecate it, but even if we
don't, could we at least ensure that this kind of rubbish doesn't
compile:

void main()
{
int x;
x  0, x += 5;
}

At present, because comma expressions are expressions, not statements,
the x  0 doesn't generate a statement has no effect error, despite
the fact that it is meaningless and gets completely discarded.


Interesting. The comma operator is probably the only one in which an
expression is evaluated only for the sake of its side effects. So
eliminating the comma operator would just get rid of that case by design.


Yes. Comma is a special case in a number of ways.


Of course, there's always the option of adding more checks or rewriting
the comma operator from expr1, expr2, expr3 to { expr1; expr2; return
expr3; }().


We hit this one often in real-world code. On German keyboards , and ; 
are on the same key, so it's a fairly easy typo. I don't think it 
happens as often when using a US keyboard.




Re: DIP19: Remove comma operator from D and provision better syntactic support for tuples

2012-09-24 Thread Don Clugston

On 23/09/12 22:40, Andrei Alexandrescu wrote:

I discussed this with Walter, and we concluded that we could deprecate
the comma operator if it helps tuples. So I started with this:

http://www.prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs/DIP19

Unfortunately, I started much cockier than I ended. The analysis in
there fails to construct a case even half strong that deprecating the
comma operator could significantly help tuples. Well it essentially
concludes that tuples are mostly fine as they are, and attempts to
embellish them syntactically are marred with unexpected problems.
Nevertheless, I sure have missed aspects all over, so contributions are
appreciated.


Thanks,

Andrei


Regarding the comma operator: I'd love to deprecate it, but even if we 
don't, could we at least ensure that this kind of rubbish doesn't compile:


void main()
{
  int x;
  x  0, x += 5;
}

At present, because comma expressions are expressions, not statements, 
the x  0 doesn't generate a statement has no effect error, despite 
the fact that it is meaningless and gets completely discarded.




Re: no-arg constructor for structs (again)

2012-09-20 Thread Don Clugston

On 20/09/12 11:09, Jonathan M Davis wrote:

On Thursday, September 20, 2012 10:11:41 Felix Hufnagel wrote:

On Thursday, 20 September 2012 at 00:14:04 UTC, Jonathan M Davis

wrote:

On Thursday, September 20, 2012 00:12:04 Felix Hufnagel wrote:

isn't it even worse?

import std.stdio;
struct S
{
int i;
this(void* p = null){this.i = 5;}
}
void main()
{
//S l(); //gives a linker error
auto k = S();
writeln(k.i); //prints 0
}


Of course that generates a linker error. You just declared a
function without
a body.

- Jonathan M Davis


sure, but it's a bit unexpected. do we need to be able to declare
empty functions?


It can be useful at module scope, and it would complicate the grammar to make
it anything else at function scope, even if there's no practical reason to use
it that way there. C/C++ (which doesn't have nested functions) also treats
that declaration as a function declaration.


but whats even more confusing: you are not allowed to declare an
no_arg constructor. but you are allowed to declare one where all
parameters have default parameters. but then, how to call it
without args? auto k = S(); doesn't work?


It's a bug. I'm pretty sure that there's a bug report for it already, but I'd
have to go digging for it to know which one it is.

- Jonathan M Davis


Bug 3438





Re: Struct problems

2012-09-18 Thread Don Clugston

On 17/09/12 20:47, Maxim Fomin wrote:

I consider current struct creation one of the confusing parts of the
language (may be the most), due to set of incompatible creation
semantics masked by same syntax, complicated by couple of semi-bugs
(7210, 1310, 4053) and naive default arguments embedding into the
language(3438).

Current creation rules look as follows (http://dpaste.dzfl.pl/a4344ad0):
1) if a struct object declaration has no initializer, its members are
default initialized to either explicit initializer in struct declaration
or type default initializer (note: actually, there are no implicit
struct constructors). If it has void initializer, it contains garbage
2) otherwise, if it has initialization form S() than:
a) if opCall member is present, it is called (must have no arguments)
b) otherwise, initialization proceed according to 1)
3) otherwise, if it has initialization form S(T1 arg1, ...), than:
a) if opCall member is present, it is called (its parameters must be
consistent with arguments)
b) otherwise, if at least one ctor exists, it is called (and again, its
parameters must be consistent with arguments)
c) otherwise, this initialization form is called struct literal and
struct members are initialized to arguments in accordance with their
order in struct declaration


There is also 4) struct static initializers, which have their own 
complicated set of rules.




This means that if you have S(), or S(x, y, x) - it is impossible to
know without looking into struct definition what is going on: a function
call (constructor or opCall) or just initialization. If naive default
argument treatment is considered, I may add that there is no sense of
setting default argument to one-argument struct constructor, since
S()-like expression would call something else (3438). By the way, .init
property may be hijacked (good news is that it doesn't affect default
initializer).

Basically, the question is, is it considered to be good, well designed
feature or not. And if not, would it be changed at some time? What was
original design of structures in D?


Struct constructors and struct literals are late additions. opCall was, 
I think, a workaround for the lack of struct constructors.


There's a comment in the source code:
 ***
  * This works by transforming a struct initializer into
  * a struct literal. In the future, the two should be the
  * same thing.
  */
 Expression *StructInitializer::toExpression()

That's the only plan I've heard of.


Re: About default parameters in variadic templates

2012-09-18 Thread Don Clugston

On 17/09/12 14:42, Andrej Mitrovic wrote:

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



A lot of code could be stripped if there was a way to set an optional
last parameter for variadics. lockstep could then be written as:

auto newLockstep(Args...)(Args args, StoppingPolicy stoppingPolicy =
StoppingPolicy.shortest)
 if (allSatisfy!(isInputRange, staticMap!(Unqual, Args)))
{
 static if (Args.length  1)
 {
 return Lockstep!(Args)(args, stoppingPolicy);
 }
 else
 {
 return args[0];
 }
}



but if you don't specify the last StoppingPolicy argument at the call
site it won't compile:

foreach (x, y; newLockstep(arr1, arr2)) { }

test.d(32): Error: template test.newLockstep does not match any
function template declaration
test.d(14): Error: template test.newLockstep(Args...) if
(allSatisfy!(isInputRange,staticMap!(Unqual,Args))) cannot deduce
template function from argument types !()(int[],int[])


That just looks like a bug to me. Please enter it in Bugzilla.




Re: [OT] Was: totally satisfied :D

2012-09-18 Thread Don Clugston

On 18/09/12 09:29, Walter Bright wrote:

I suppose I have a more pragmatic view, due to my background in
non-computer engineering.

 It's all like that.

There are a couple of good reasons for that.

1. Not every engineer is a rock star. In fact, very few of them are. I
tend to snicker at companies that insist they only hire the top 1%. It
seems that about 90% of the engineers out there must be in that top 1% g.

2. It costs too much money to do perfect engineering. You wouldn't be
able to afford those products. Do you have $10,000 to spend on a tablet?



Software is a lot better, too. It really is.


I don't think that's true, except in terms of the range of functionality.

The interesting thing is if you compare computer hardware from 1985 with 
hardware from today. It is dramatically better, in every respect, 
without exception.


But that isn't true of software. Tex is ancient, and yet it's not easy 
to find *any* recent software of similar quality.


When I was a kid, I muse to make games and save them on cassette tapes. 
The tapes failed pretty often, so that my work was lost.


Last week, my kids made some games using online Flash/JS-based websites. 
Due to bugs in those websites, sometimes when they go to save, their 
work is lost. I find that appalling.




Re: built-in array ptrEnd

2012-09-18 Thread Don Clugston

On 17/09/12 18:40, bearophile wrote:

monarch_dodra:


IMO, this should really be built-in, in particular, since, in my
understanding, an array is internally represented by the ptr and
ptrEnd pair anyways.


Currently this is not true, take a look at the ABI part in the D site.
Currently it's a pointer and length. Walter and/or Andrei discussed the
idea of turning them into two pointers, but I don't know if and why that
change was refused.


Because it would be a mistake. You can efficiently get from (ptr, 
length) to (ptr, endPtr) but the reverse is not true.




Re: [Issue 8660] New: Unclear semantics of array literals of char type, vs string literals

2012-09-14 Thread Don Clugston

On 14/09/12 14:50, monarch_dodra wrote:

On Friday, 14 September 2012 at 11:28:04 UTC, Don wrote:

--- Comment #0 from Don clugd...@yahoo.com.au 2012-09-14 04:28:17
PDT ---
Array literals of char type, have completely different semantics from
string
literals. In module scope:

char[] x = ['a'];  // OK -- array literals can have an implicit .dup
char[] y = b;// illegal

A second difference is that string literals have a trailing \0. It's
important
for compatibility with C, but is barely mentioned in the spec. The
spec does
not state if the trailing \0 is still present after operations like
concatenation.


I think this is the normal behavior actually. When you write char[] x =
['a'];, you are not actually newing (or dup-ing) any data. You are
just letting x point to a stack allocated array of chars.


I don't think you've looked at the compiler source code...
The dup is in e2ir.c:4820.


So the
assignment is legal (but kind of unsafe actually, if you ever leak x).


Yes it's legal. In my view it is a design mistake in the language.
The issue now is how to minimize the damage from it.



On the other hand, you can't bind y to an array of immutable chars, as
that would subvert the type system.

This, on the other hand, is legal.
char[] y = b.dup;

I do not know how to initialize a char[] on the stack though (Appart
from writing ['h', 'e', 'l', ... ]). If utf8 also gets involved, then I
don't know of any workaround.

I think a good solution would be to request the m prefix for literals,
which would initialize them as mutable:
x = msome mutable string;


A second difference is that string literals have a trailing \0. It's
important
for compatibility with C, but is barely mentioned in the spec. The
spec does
not state if the trailing \0 is still present after operations like
concatenation.

CTFE can use either, but it has to choose one. This leads to odd effects:

string foo(bool b) {
string c = ['a'];
string d = a;
if (b)
return c ~ c;
else
return c ~ d;
}

char[] x = foo(true);   // ok
char[] y = foo(false);  // rejected!

This is really bizarre because at run time, there is no difference
between
foo(true) and foo(false). They both return a slice of something
allocated on
the heap. I think x = foo(true) should be rejected as well, it has an
implicit
cast from immutable to mutable.


Good point. For anybody reading though, the actual code example should be
enum char[] x = foo(true);   // ok
enum char[] y = foo(false);  // rejected!


No it should not.
The code example was correct. These are static variables.




I think the best way to clean up this mess would be to convert char[]
array
literals into string literals whenever possible. This would mean that
string
literals may occasionally be of *mutable* type! This would means that
whenever
they are assigned to a mutable variable, an implicit .dup gets added
(just as
happens now with array literals). The trailing zero would not be duped.
ie:
A string literal of mutable type should behaves the way a char[] array
literal
behaves now.
A char[] array literal of immutable type should behave the way a
string literal
does now.


I think this would work with my m suggestion


Not necessary. This is only a question about what happens with the 
compiler internals.


Re: LDC

2012-09-13 Thread Don Clugston

On 05/09/12 20:12, Jacob Carlborg wrote:

On 2012-09-05 14:32, Piotr Szturmaj wrote:

angel wrote:

Check out LDC web-page ...
In github we see they're up to date - merging 2.060


What's the status of SEH on Windows?


It's not looking good, at least not for 32bit. Borland has some kind of
patent on something related to SEH. Due to this, the LLVM/Clang
developers won't implement SEH for Windows.


That sounds paranoid to me. I believe the patent is essentially a 
workaround for the absence of thread-local variables on 16-bit Windows.


In D we have working thread-local variables even on Windows versions 
that don't support them, thanks to Rainer's brilliant work. Which gives 
very many ways of implementing exception handling on Windows.


Re: filter out compile error messages involving _error_

2012-09-10 Thread Don Clugston

On 10/09/12 02:31, Jonathan M Davis wrote:

On Monday, September 10, 2012 02:16:19 Timon Gehr wrote:

Don has expressed the desire to weed those out completely.


If he can do it in a way that leaves in all of the necessary information, then
great, but you need to be able to know what the instantiation chain was.

- Jonathan M Davis


Yes, that's the idea. It's pretty much working for CTFE now (you get a 
complete call stack, with no spurious error messages).




Re: bigint - python long

2012-09-06 Thread Don Clugston

On 05/09/12 21:23, Paul D. Anderson wrote:

On Wednesday, 5 September 2012 at 18:13:40 UTC, Ellery Newcomer wrote:

Hey.

Investigating the possibility of providing this conversion in pyd.

Python provides an api for accessing the underlying bytes.

std.bigint seemingly doesn't. Am I missing anything?


No, I don't believe so. AFAIK there is no public access to the
underlying array, but I think it is a good idea.

I suspect the reason for not disclosing the details is to disallow
anyone putting the data into an invalid state. But read-only access
would be safe.


No, it's just not disclosed because I didn't know the best way to do it.
I didn't want to put something in unless I was sure it was correct.
(And a key part of that, is what is required to implement BigFloat).



Re: How to have strongly typed numerical values?

2012-09-05 Thread Don Clugston

On 05/09/12 03:42, bearophile wrote:

Nicholas Londey:


for example degrees west and kilograms such that they cannot be
accidentally mixed in an expression.


Using the static typing to avoid similar bugs is the smart thing to do :-)


I'd be interested to know if that idea is ever used in real code. I 
mean, it's a classic trendy template toy, but does anyone actually use it?


I say this because I've done a lot of physics calculation involving 
multiple complicated units, but never seen a use for this sort of thing.
In my experience, problems involving units are easily detectable (two 
test cases will catch them all).
The most insidious bugs are things like when you have used constants at 
25'C instead of 20'C, or when you have a sign wrong.


Re: Can DMD be built with g++?

2012-09-04 Thread Don Clugston

On 30/08/12 22:21, Andrej Mitrovic wrote:

On 8/30/12, Alex Rønne Petersen a...@lycus.org wrote:

How are you building, what platform, etc...


Ah geez I forgot there's a makefile (doh!), I need to look into
passing the right flags first. I'm trying this on win32 via MinGW btw.



That's a different story. Dunno if anyone has tried that before.
It would be a miracle if the Windows makefile worked with g++, and AFAIK 
the Posix makefile is only set up for posix.


Re: Trouble creating a formatted assert wrapper

2012-09-04 Thread Don Clugston

On 03/09/12 23:48, Chris Nicholson-Sauls wrote:

On Monday, 3 September 2012 at 11:17:39 UTC, Chris Nicholson-Sauls wrote:

1) Empty array stands in for empty variadic. [snip]

In reality, though, we have neither of these things. [snip]


Turns out, I was quite wrong, and I'm happy to be.  Empty array is
accepted for typesafe variadics just fine ... I'm not sure now why I
thought otherwise.

Of course, our tangent is really sort of moot, since the brackets would
be required for any pattern with a suffix matching the optional
arguments anyhow, at which point there's little point in having the
variadic argument.  I reiterate my impression that magical __FILE__ and
__LINE__ should be provided by some other means.


It was a special-case hack to fix a special-case need. It was extremely 
easy to implement (about 2 hours work) and has been very successful in 
fixing that need. Everything else that anyone has talked about is at 
least ten times as complicated, and doesn't seem to offer significant 
advantages.


It's really easy to come up with over-engineered solutions to these 
sorts of things.


Re: Trouble creating a formatted assert wrapper

2012-09-04 Thread Don Clugston

On 04/09/12 11:43, Chris Nicholson-Sauls wrote:

On Tuesday, 4 September 2012 at 09:24:26 UTC, Don Clugston wrote:

On 03/09/12 23:48, Chris Nicholson-Sauls wrote:

I reiterate my impression that magical __FILE__ and
__LINE__ should be provided by some other means.


It was a special-case hack to fix a special-case need. It was
extremely easy to implement (about 2 hours work) and has been very
successful in fixing that need. Everything else that anyone has talked
about is at least ten times as complicated, and doesn't seem to offer
significant advantages.

It's really easy to come up with over-engineered solutions to these
sorts of things.


How difficult would hidden params, triggered by usage, be?  Ie: my
function makes use of __CALL_FILE and __CALL_LINE variables by name,
therefore they are tacked on  (as const, presumably) and always passed,
thanks to diabolic compiler sorcery.  The current solution is fine in a
majority of cases, at least so far, but there are going to be moments
like what the OP had, and these moments are discouraging especially to
newcomers.


I don't know how that could be done. You need to know the function 
signature whenever you call the function. If you make the signature 
dependent on the function body, it cannot work unless you have the 
source code of the function. The compiler is able to add hidden 
variables for things like 'this' because it can work out if it is 
required just by looking at the types involved in the function 
declaration. But in this case, it can't get it from the signature.


The default argument method we are currently using is a nice trick, 
because even though default arguments aren't part of the function type, 
the compiler still sees them in the function signature, so it knows to 
do a bit of magic.


It's also easy to get nasty forward reference errors when you do that 
sort of thing.





I won't pretend to know if it would be easy or not; you're a heck of a
lot more familiar with the compiler's code than I am.  But it certainly
seems straightforward.





Re: handful and interval

2012-09-03 Thread Don Clugston

On 02/09/12 22:42, SomeDude wrote:

On Sunday, 2 September 2012 at 15:09:50 UTC, deadalnix wrote:

Le 02/09/2012 16:51, Jacob Carlborg a écrit :

I really don't like the name handful. What would be the difference
compared to a regular set container? To me it sounds like we should have
a standard set container in Phobos, std.container.set.



+1, and we are back to the allocator design.


+2 on the basis of typical real world (if I may says so) usage. It
calls for a set container, both mutable and immutable.

For a handful of values (say 5 or less), I'm not even sure the O(1)
method is faster than the O(n) one.

As for the intervals, I suppose one would have to define open intervals,
because I think they would be much more useful than closed ones when the
intervals are contiguous (in particular with floats/doubles).
One must be able to translate x0 = x  x1 in intervals else they are
practically useless for anything else than integers and other discrete
values.


But practically everything on a computer uses discrete values. Floating 
point numbers always do, for example; they are *not* mathematical real 
numbers with infinite precision.
For floats and doubles, any non-empty interval can be expressed using 
closed intervals.


Use the nextUp() and nextDown() to convert between open and closed 
intervals.


[ x .. y ] == ( nextDown(x) .. nextUp(y) )
( x .. y ) == [ nextUp(x) .. nextDown(y) ]


In general:

Fully closed interval: cannot express an empty interval.
Fully open interval: cannot express a maximum-sized interval. Empty 
intervals can be expressed but not uniquely.

Half-open: not closed under negation.

Either of the first two are reasonable choices for arithmetic 
applications. The third is broken for anything that allows negative values.




Re: alias this

2012-09-03 Thread Don Clugston

On 01/09/12 15:16, Carl Sturtivant wrote:

What is the design logic behind

364.d(9): Error: alias this compileme364.number.__anonymous there can
be only one alias this

--- not a complaint, I'd just like to hear opinion of the basis of
the above restriction from experts.


This is a limitation in implementation.  According to TDPL, there will be
multiple alias this allowed in the final implementation.

See this bug: http://d.puremagic.com/issues/show_bug.cgi?id=6083



Perhaps you can point me at a way to get a short list of features like
this that we might say are strategically limited at the moment
(perhaps even to the extent of being absent even), but definitely
intended for complete implementation eventually.



http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel#Roadmap



Re: CTFE question

2012-09-03 Thread Don Clugston

On 28/08/12 19:40, Philippe Sigaud wrote:

On Tue, Aug 28, 2012 at 2:07 PM, Chris Cain clc...@uncg.edu wrote:

On Tuesday, 28 August 2012 at 11:39:20 UTC, Danny Arends wrote:


Ahhh I understand...

As a follow up, is it then possible to 'track' filling a
large enum / immutable on compile time by outputting a msg
every for ?

I'm generating rotation matrices for yaw, pitch and roll
at compile time which can take a long time depending on
how fine grained I create them.



I'm pretty sure there isn't. However, if you're just trying to develop/test
your algorithm, you could write a program that runs it as a normal function
(and just use writeln) as you develop it. After it's done, you remove the
writelns, mark the function as pure and it should work exactly the same in
CTFE.


Godd adivce, except beware of using ++ and --, they don't work at
compile-time. I'm regularly caught unaware by this, particularly while
looping.


Really? That's scary. Is there a bug report for this?


Re: Function pointers/delegates default args were stealth removed?

2012-08-28 Thread Don Clugston

On 27/08/12 16:16, Steven Schveighoffer wrote:

On Sun, 26 Aug 2012 18:26:40 -0400, Manu turkey...@gmail.com wrote:


I just updated to 2.60 and found errors throughout my code where function
pointers default args no longer work.
*Every single project* I've written in D, 5 projects, don't work anymore,
including my projects at work.


OK, I've read all the posts on this, and this is what I think would
solve the problem:

1. default parameters are part of the function pointer type, because a
function pointer has a type.
2. The mangled name of the function that is assigned to that function
pointer does *not* have default parameters mangled in.  Only the
function pointer type has them.
3. Since the default parameters are part of the type, but not defined by
the function it points to, you can use interchangeably functions of the
same type which define default parameters or not (or define different
ones).  The default parameters follow the function pointer variable.


This sounds like sloppy thinking.
I _think_ what you are saying is that there should be implicit 
conversions from one function pointer type, to any other that has the 
same basic declaration, but different default arguments.


But then you get problems with IFTI.
void foo( void function(int x), double) {}
void foo( void function(int x), int) {}

void function(int x = 10) bar;

foo(bar, 5); // fails -- ambiguous. Both overloads match with implicit 
conversions.



But really, it seems to me that this whole feature is just syntax sugar 
for one special case of currying.


Re: More on vectorized comparisons

2012-08-27 Thread Don Clugston

On 24/08/12 15:57, bearophile wrote:

It's just syntax sugar for a very obscure operation,


It's an operation included in Cilk Plus, I think Intel devs know
enough what they are doing.
And I think code like this is a common need:

if (a[]  0) {
  // ...
}

and it's somewhat ambiguous -- is it allowed to use short-circuit
evaluation?


That code means:

foreach (i; 0 .. a.length) {
  if (a[i]  0) {
  // ...
  }
}

Here I don't see problems caused by short circuit evaluation.


Wow. Then I misunderstood, and it's even less appropriate for D than I 
thought.


vote -= int.max;

Worst syntax I've seen in a very long time.


Re: More on vectorized comparisons

2012-08-24 Thread Don Clugston

On 24/08/12 00:13, bearophile wrote:

Sean Cavanaugh:


Well, right now the binary operators == != = =  and  are required
to return bool instead of allowing a user defined type, which prevents
a lot of the sugar you would want to make the code nice to write.


The hypothetical D sugar I was looking for is this, where 'a', 'b' and
'c' are normal dynamic arrays of doubles (not of float[4] of double[2])
(currently this code is a syntax error):

if (a[]  0)
 b[] += c[];


The front-end is able to implement those two lines of code as it likes,
like seeing those normal arrays as arrays of double[2] (or double[4] on
more modern CPUs) and put there all the needed intrinsics or assembly
needed to implement that semantics.

So what's the problem the  operator causes in this code?

Bye,
bearophile


It's just syntax sugar for a very obscure operation, and it's somewhat 
ambiguous -- is it allowed to use short-circuit evaluation?
Mathematically, it doesn't make sense. You can compare scalars, but 
ordered comparison of vectors is a bit nonsensical, unless it is 
element-wise.

Usually, a[]  0, a[]  0, and a[] == 0 will all be false.

Most likely, you really meant  dot(a[])  0.

Something like

if ( all( a[]  0 ) )
b[] += c[];

is more reasonable. But an implicit 'reduce' in a vector operation has 
little to commend it, I think.




Re: Ascii matters

2012-08-23 Thread Don Clugston

On 23/08/12 05:05, bearophile wrote:

Sean Kelly:


I'm clearly missing something.  ASCII and UTF-8 are compatible.
 What's stopping you from just processing these as if they were UTF-8
strings?


std.algorithm is not closed
(http://en.wikipedia.org/wiki/Closure_%28mathematics%29 ) on UTF-8, its
operations lead to UTF-32.


Which operations in std.algorithm over map 0-0x7F into higher characters?


Re: NaNs Just Don't Get No Respect

2012-08-21 Thread Don Clugston

On 20/08/12 22:21, cal wrote:

On Monday, 20 August 2012 at 19:28:33 UTC, Peter Alexander wrote:

On Sunday, 19 August 2012 at 22:22:28 UTC, Walter Bright wrote:

 I find it more likely that the NaN will go unnoticed and
 cause rare bugs.

NaNs in your output are pretty obvious. For example, if your
accounting program prints NAN for the amount on the payroll
cheques, someone is guaranteed to notice. But if it's a few cents off
in your disfavor, it might take you years to discover there's a problem.

Critical systems also would find a NaN command a lot easier to detect
than an off-by-two command, and would be able to shut down and engage
the backup.


The problem is that it's easy for even NaN's to be filtered out.

float x = 0.0f;
float y; // oops
float z = min(x, y); // NaN has disappeared, unnoticed!

My argument is that conservative compile time errors on uninitialised
variables are more likely to catch these errors.


I just tried this:

float a, b = 10;
writeln(min(a, b), , , fmin(a, b));

Result:
nan, 10

I think that is incorrect - both should give NaN. The scientific viz
software I use at work returns NaN for any numerical operation on NaN
values, means, smoothing, etc.


No, it's the other way around.
The IEEE 754 standard defines min(x, NaN) == min(NaN, x) == x.

According to the C standard, fmin() should be returning 10, as well.
There is a bug in fmin().

However min() and max() are extremely unusual in this respect. Almost 
everything else involving a NaN returns NaN.






Re: NaNs Just Don't Get No Respect

2012-08-20 Thread Don Clugston

On 18/08/12 05:03, bearophile wrote:

F i L:


Why would it matter what is normal?


It matters to me because I am curious.

Why aren't my friends that work or study chemistry writing free small
online articles like my programmerCS friends do? Maybe it's systematic
differences in their brain brain? Or it's just more easy to talk about
coding compared to botany and chemistry and making engines? Or maybe
programmers don't know what they are doing? Or maybe it's just I am not
looking in the right places? :-)

Bye,
bearophile



They write journal articles instead. Producing journal articles have 
never been of major importance for IT, but they are crucial for science.


And if it isn't a new, publishable result, you're more likely to 
contribute to something like Wikipedia, than to write a blog post.


OTOH some people do blog, for example, http://terrytao.wordpress.com/
who is one of the top mathematicians on the planet.


Re: DMD diagnostic - any way to remove identical lines from final dmd error log?

2012-08-14 Thread Don Clugston

On 13/08/12 18:47, Dmitry Olshansky wrote:

I seriously consider writing a simple postprocessor for dmd's output.
Once dmd became able to recover from errors and crawl on it started to
produce horrific amounts of redundant text on failure.

Observe for instance that there are only 6 + 2 = 8 lines of interest:


Spurious or repeated error messages should be considered to be bugs.
Please put test cases in Bugzilla. A long time ago, the compiler used to 
spew reams of garbage all the time. Now it rarely happens.



Other food for thought is to try to indicate explicitly which errors
are related vs unrelated, which are collateral, like failed template
instantiation that rolls out the whole path of failure (but one have to
read the text carefully to get where it starts).


That's already happening. Supplemental messages don't have the word 
'Error' at the start of the error message.

There are still cases where



Re: Which D features to emphasize for academic review article

2012-08-14 Thread Don Clugston

On 14/08/12 05:03, TJB wrote:

On Monday, 13 August 2012 at 10:11:06 UTC, Don Clugston wrote:


 ... I have come to believe that there are very few algorithms
originally designed for integers, which also work correctly for
floating point.

Integer code nearly always assumes things like, x + 1 != x, x == x,
(x + y) - y == x.


for (y = x; y  x + 10; y = y + 1) {  }

How many times does it loop?


Don,

I would appreciate your thoughts on the issue of re-implementing numeric
codes like BLAS and LAPACK in pure D to benefit from the many nice
features listed in this discussion.  Is it feasible? Worthwhile?

Thanks,

TJB


I found that when converting code for Special Functions from C to D, the 
code quality improved enormously. Having 'static if' and things like 
float.epsilon as built-ins makes a surprisingly large difference. It 
encourages correct code. (For example, it makes any use of magic numbers 
in the code look really ugly and wrong). Unit tests help too.


That probably doesn't apply so much to LAPACK and BLAS, but it would be 
interesting to see how far we can get with the new SIMD support.




Re: DMD diagnostic - any way to remove identical lines from final dmd error log?

2012-08-14 Thread Don Clugston

On 14/08/12 08:59, Don Clugston wrote:

On 13/08/12 18:47, Dmitry Olshansky wrote:

I seriously consider writing a simple postprocessor for dmd's output.
Once dmd became able to recover from errors and crawl on it started to
produce horrific amounts of redundant text on failure.

Observe for instance that there are only 6 + 2 = 8 lines of interest:


Spurious or repeated error messages should be considered to be bugs.
Please put test cases in Bugzilla. A long time ago, the compiler used to
spew reams of garbage all the time. Now it rarely happens.


Other food for thought is to try to indicate explicitly which errors
are related vs unrelated, which are collateral, like failed template
instantiation that rolls out the whole path of failure (but one have to
read the text carefully to get where it starts).


That's already happening. Supplemental messages don't have the word
'Error' at the start of the error message.


One fairly easy way to solve this, would be that once a template 
*instantiation* has failed, the template *definition* would be marked as 
doubtful, and any further instantiation using that definition would have 
all error messages suppressed. If an error occurred, a single error 
would be produced stating that the template instantiation failed.


The downside would be that if the template instantiation failed for a 
completely different reason the second time, its root cause error would 
not be shown. But this latest release is the only time such errors have 
been shown anyway.




Re: DMD diagnostic - any way to remove identical lines from final dmd error log?

2012-08-14 Thread Don Clugston

On 14/08/12 11:32, Paulo Pinto wrote:

On Tuesday, 14 August 2012 at 08:48:14 UTC, Don Clugston wrote:

On 14/08/12 08:59, Don Clugston wrote:

On 13/08/12 18:47, Dmitry Olshansky wrote:

I seriously consider writing a simple postprocessor for dmd's output.
Once dmd became able to recover from errors and crawl on it started to
produce horrific amounts of redundant text on failure.

Observe for instance that there are only 6 + 2 = 8 lines of interest:


Spurious or repeated error messages should be considered to be bugs.
Please put test cases in Bugzilla. A long time ago, the compiler used to
spew reams of garbage all the time. Now it rarely happens.


Other food for thought is to try to indicate explicitly which errors
are related vs unrelated, which are collateral, like failed template
instantiation that rolls out the whole path of failure (but one have to
read the text carefully to get where it starts).


That's already happening. Supplemental messages don't have the word
'Error' at the start of the error message.


One fairly easy way to solve this, would be that once a template
*instantiation* has failed, the template *definition* would be marked
as doubtful, and any further instantiation using that definition would
have all error messages suppressed. If an error occurred, a single
error would be produced stating that the template instantiation failed.

The downside would be that if the template instantiation failed for a
completely different reason the second time, its root cause error
would not be shown. But this latest release is the only time such
errors have been shown anyway.


Personally I loved the way Turbo Pascal used to work with compile
failure on the first error.

Thanks to the fast compile times, it was easier and faster to
fix-compile-find_next_error, than try to sort out the real errors from a
dump of error messages.


To the best of my knowledge, DMD gives very few error messages which are 
not real. Every release, I eliminate a couple more spurious ones. It's 
starting to be difficult to find them.


Seriously, if you are finding ANY error messages for things which are 
not real errors, that is a bug.





But I seem to be in the minority regarding compiler error messages.

--
Paulo





Re: Which D features to emphasize for academic review article

2012-08-14 Thread Don Clugston

On 14/08/12 12:31, Mehrdad wrote:

On Saturday, 11 August 2012 at 05:41:23 UTC, Walter Bright wrote:

On 8/10/2012 9:55 PM, F i L wrote:

On the first condition, without an 'else z = ...', or if the
condition was removed at a later time, then you'll get a compiler
error and be forced to explicitly assign 'z' somewhere above using
it. So C# and D work in similar ways in this respect except that C#
catches these issues at compile-time, whereas in D you need to:
  1. run the program
  2. get bad result
  3. hunt down bug


However, and I've seen this happen, people will satisfy the compiler
complaint by initializing the variable to any old value (usually 0),
because that value will never get used. Later, after other things
change in the code, that value suddenly gets used, even though it may
be an incorrect value for the use.



Note to Walter:

You're obviously correct that you can make an arbitrarily complex
program to make it too difficult for the compiler to enforce
initialization, the way C# does (and gives up in some cases).

What you seem to be missing is that the issue you're saying is correct
in theory, but too much of a corner case in practice.

C#/Java programmers ___rarely___ run into the sort of issue you're
mentioning, and even when they do, they don't have nearly as much of a
problem with fixing it as you seem to think.

The only reason you run into this sort of problem (assuming you do, and
it's not just a theoretical discussion) is that you're in the C/C++
mindset, and using variables in the C/C++ fashion.
If you were a C#/Java Programmer instead of a C++ Programmer, you
simply _wouldn't_ try to make things so complicated when coding, and you
simply _wouldn't_ run into these problems the way you /think/ you would,
as a C++ programmer.


Regardless, it looks to me like you two are arguing for two orthogonal
issues:

F i L:  The compiler should detect uninitialized variables.
Walter: The compiler should choose initialize variables with NaN.


What I'm failing to understand is, why can't we have both?

1. Compiler _warns_ about uninitialized variables (or scalars, at
least) the same way C# and Java do, __unless__ the user takes the
address of the variable, in which case the compiler gives up trying to
detect the flow (like C#).
Bonus points: Try to detect a couple of common cases (e.g. if/else)
instead of giving up so easily.

2. In any case, the compiler initializes the variable with whatever
default value Walter deems useful.


Then you get the best of both worlds:

1. You force the programmer to manually initialize the variable in most
cases, forcing him to think about the default value. It's almost no
trouble for

2. In the cases where it's not possible, the language helps the
programmer catch bugs.


Why the heck D avoids #1, I have no idea.


DMD detects uninitialized variables if you compile with -O. It's hard to 
implement the full Monty at the moment, because all that code is in the 
backend rather than the front-end.



It's one of the _major_ features of C# and Java that help promote
correctness, and #1 looks orthogonal to #2 to me.


Completely agree.
I always thought the intention was that assigning to NaN was simply a 
way of catching the difficult cases that slip through compile-time 
checks. Which includes the situation where the compile-time checking 
isn't yet implemented at all.
This is the first time I've heard the suggestion that it might never be 
implemented.


The thing which is really bizarre though, is float.init. I don't know 
what the semantics of it are.


Re: Which D features to emphasize for academic review article

2012-08-13 Thread Don Clugston

On 12/08/12 01:31, Walter Bright wrote:

On 8/11/2012 3:01 PM, F i L wrote:

Walter Bright wrote:

I'd rather have a 100 easy to find bugs than 1 unnoticed one that
went out in
the field.


That's just the thing, bugs are arguably easier to hunt down when
things default
to a consistent, usable value.


Many, many programming bugs trace back to assumptions that floating
point numbers act like ints. There's just no way to avoid knowing and
understanding the differences.


Exactly. I have come to believe that there are very few algorithms 
originally designed for integers, which also work correctly for floating 
point.


Integer code nearly always assumes things like, x + 1 != x, x == x,
(x + y) - y == x.


for (y = x; y  x + 10; y = y + 1) {  }

How many times does it loop?




Re: Incomprehensible compiler errors

2012-07-31 Thread Don Clugston

On 31/07/12 00:54, Stuart wrote:

On Monday, 30 July 2012 at 21:40:35 UTC, Walter Bright wrote:


A ModuleInfo is generated for each compiled module and inserted into
its corresponding .obj file. If the linker cannot find it, then it is
likely that you need to specify that .obj on the link command.


Ah, it would seem that my problem is with DFL not compiling. Look guys,
I'm about ready to give up here. I like the idea of D, but it's like
using fucking Linux: Absolutely everything needs to be compiled before
you can use it; and nothing will compile because you need to do fifty
other goddamn things that aren't mentioned in the readme, so you have to
post on dozens of sodding forums for a week hoping someone throws you a
bone.




All I want is to be able to write a GUI application using phrases like
button1.dock = Fill. Is that so much to ask? Apparently it is.

DFL won't compile. D-IDE doesn't work at all. VisualD crashes all the
time. The Eclipse IDE plugin doesn't work either. None of the IDEs have
any kind of reliable intellisense. The optional module keywords aren't
optional. The whole fucking thing's a shambles, just like everything
else designed for Linux.

It's really getting on my tits. Even using MFC is easier than this.


Yeah, we still have *miles* to go on the toolchain. As a community we've 
been putting most of our effort into getting the compiler stable, and to 
a lesser extent working on the the standard library. Most of the other 
things are one-man shows.

The Eclipse plugin and DFL have both been abandoned for years.
Mono-D and VisualD are progressing quite well but again they are only 
one-man shows.


We need more people.


  1   2   3   >