Re: sorting failed error

2012-07-30 Thread Timon Gehr

On 07/30/2012 02:36 PM, maarten van damme wrote:

For fun I started implementing a program that uses genetics
algorithm's to solve the travelling salesman problem. I want to sort
an array of chromosome structures according to their fitness. I now
get the error:

core.exception.AssertError@C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm.
d(6714): Failed to sort range of type chromosome[]. Actual result is: [chromosom
e([city(20, 0), city(25, 25), city(10, 65), city(50, 50), city(75, 30), city(0,
10)]), chromosome([city(10, 65), city(50, 50), city(25, 25), city(75, 30), city(
...

I have no idea what is wrong with my code and the error is not very informative.
Does anyone have any idea as to what the problem could be?

(full code is at
https://dl.dropbox.com/u/15024434/travelling_salesman.d , If it's not
something obvious then I'm going to try to reduce it to something as
small as possible)

Maarten


I'd claim it is a 32 bit specific compiler bug, but it is likely that
someone will differ.



reduced test case:

float foo(){
  auto f = 3f;
  return 1/f;
}
void main(){ assert(foo() == foo()); }

The problem is presumably that one of the operands is truncated to
float while the other remains at register precision.



workaround:

bool fitnessCompare(chromosome first,chromosome second){
  auto a = fitness(first), b = fitness(second);
  return a>b;
}

(the reason schwartzSort works is because it caches the fitnesses,
which is better anyway.)




I realize that the code is just for fun, but I have some comments:

- don't .dup stuff just in order to index directly. it never has
any effect other than performance degradation. (this could be a
compiler warning)

- crossOver and mutate mutate their parameters in-place. I assume this
is by mistake. reproduce effectively inserts every element a couple
times because of this -- this is why the bug manifests reliably.
(const, immutable annotations?)

- make use of $

int from=uniform(0,victim.dna.length);
int to=uniform(0,victim.dna.length);
swap(victim.dna[from],victim.dna[to]);

=>

swap(victim.dna[uniform(0,$)],
 victim.dna[uniform(0,$)]);

- sort is in-place

workers=array(sort!(fitnessCompare)(workers));

=>

sort!fitnessCompare(workers)

- mark local functions static if they do not need to access the
enclosing context.

- use size_t for array iteration variables (if necessary)

for(int x=0;x

for(size_t x=1;x=2 is guaranteed, but it is
an error prone pattern.

- another way to do it is to drop the loop completely and to use
ranges instead:

return zip(cities,cities.drop(1))
  .map!(a=>distance(a.expand))
  .reduce!"a+b";


The benefit is that this is now obviously correct.


You might also want to consider not building up the cities array
and computing the terms at the boundary explicitly instead:

return distance(city(0,0), victim.dna[0]) +
   distance(victim.dna[$-1], city(0,0)) +
   zip(victim.dna, victim.dna.drop(1))
  .map!(a=>distance(a.expand))
  .reduce!"a+b";

The goal is to craft the shortest code possible that is still
efficient and easy to follow.

- type deduction?


further comments whose application does not lead to immediate benefit:

- in contracts are better specified in their dedicated section to push
the requirements onto the caller.

- consider for(;;) as a means for indefinite looping.

- the convention is upper case for type names


Re: sorting failed error

2012-07-30 Thread Timon Gehr

On 07/30/2012 03:52 PM, monarch_dodra wrote:

...
Your looks OK, and I doubt you are mutating. I only see floating point
gotchas:
If a chromosome travels nothing, then his fitness is 1/0 = NaN.



1/0 evaluates to Inf


NaN then compares false with everything, making it un-transitive, and
potentially breaking your cmp. COuld you try the algo with "return
1/(1+travelled)".

That, or because of the non-deterministic nature  of floating point
calculation,


Floating-point computation is deterministic.


I'd create an array containing all the fitnesses, and sort
using that. This should avoid any "re-evaluation error".




Re: sorting failed error

2012-07-30 Thread Timon Gehr

On 07/31/2012 12:30 AM, maarten van damme wrote:

2012/7/31 Timon Gehr:

...
further comments whose application does not lead to immediate benefit:

- in contracts are better specified in their dedicated section to push
the requirements onto the caller.

- consider for(;;) as a means for indefinite looping.

- the convention is upper case for type names


Thank you very much for this criticism, I'm relatively new to
programming and these mistakes/points are the kind off things you
can't learn from reading a book or two.



I'm glad to help.


I have one little question about one of the last points though
why use for(;;)?


Well, as stated, there is no benefit.


As far as I can tell this simply reduces readability from while(true).


That is entirely a matter of preference.


Is there any reason for this?


I like it more because it says "loop".
while(true) says: "loop as long as 'true' still holds", which is silly.


Re: Detector for unused variables

2012-07-31 Thread Timon Gehr

On 07/31/2012 11:55 AM, Minas wrote:

I agree that having the compiler make warnings about unused
variables is a really good idea!!!

Java has it and when I program in eclipse it's really useful
because the editor can highlight the particular lines.


An editor can be configured to point it out even if it is not in the
language, if it is considered useful.


Re: Why must bitfields sum to a multiple of a byte?

2012-07-31 Thread Timon Gehr

On 07/31/2012 06:57 PM, Era Scarecrow wrote:

On Tuesday, 31 July 2012 at 16:48:37 UTC, Andrej Mitrovic wrote:

On 7/31/12, Era Scarecrow  wrote:

I wonder, is it really a bug? If you are going to have it fill a
whole size it would fit anyways, why even put it in as a bitfield?
You could just declare it separately.


I don't really know, I'm looking at this from a point of wrapping C++.
I haven't used bitfields myself in my own code.


I'd say it's not a bug since C/C++ is free to reorder the fields you'd
need to tinker with it anyways; HOWEVER if you still need to be able to
have it then who's to stop you from doing it?

I think more likely a flag/version or some indicator that you didn't
make a mistake, such as making them depreciated so it complains to you.
Kinda like how you can't make assignments in if statements or do useless
compares, it's an error and helps prevent issues that are quite
obviously mistakes.


This is obviously a mistake in the bitfield implementation. What else
could be concluded from the error message:

std\bitmanip.d(76): Error: shift by 32 is outside the range 0..31

Requesting a 32 bit or 64 bit member on the other hand is not a
mistake, and it is not useless, therefore the analogy breaks down.

(Also IMO, the once-in-a-year wtf that is caused by accidentally
assigning in an if condition does not justify special casing assignment
expressions inside if conditions. Also, what is an useless compare?)


Re: Detector for unused variables

2012-08-01 Thread Timon Gehr

On 08/01/2012 12:38 PM, bearophile wrote:

Regan Heath:


Indeed. IIRC Walter's rationale on things like this has always been
that they belong in 3rd party tools.


Walter is not always right.



It's why the DMD front end is available for use, so people can create
tools like this, syntax highlighters, re-formatters, dependency tree
diagrams, or... you name it.


Detecting unused variables is a core feature,


No. This mustn't be part of the language.

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


it belongs in the
compiler, like compile-time array bound tests and other errors currently
detected by DMD. This allows everyone to use it with minimum work, so
everyone enjoys it, and it requires less work to be implemented because
the compiler already does lot of analysis.



It is not an error. Making things that are not errors illegal is prone
to introduce bugs into code using __traits(compiles).

This can be a warning at best.


Re: How to use "read_bool"?

2012-08-02 Thread Timon Gehr

On 08/03/2012 06:17 AM, Zeh wrote:

Hi, i am just a newbie trying learn D. But, i get having some trouble
with "read_bool". More specifically on program of this lesson:

import std.stdio;
import std.conv;
import std.string;

void main()
{
write("How many are we? ");
int personCount;
readf(" %s", &personCount);

write("How many bicycles are there? ");
int bicycleCount;
readf(" %s", &bicycleCount);

write("What is the distance to the beach? ");
int distance;
readf(" %s", &distance);

bool existsCar = read_bool("Is there a car? ");
bool existsLicense =
read_bool("Is there a driver license? ");

When i try compile this, i get the following errors:

hello.d|43|Error: undefined identifier read_bool|
hello.d|44|Error: undefined identifier read_bool|
||=== Build finished: 2 errors, 0 warnings (0 minutes, 0 seconds) ===|

So, someone know what's happening? What is the correct way to use the
Read_bool?

Thanks for everyone!



presumably read_bool is part of the tutorial. Otherwise you may use this:

bool read_bool(){
auto str = readln()[0..$-1];
switch(str){
case "true", "y", "ye", "yes": return true;
case "false", "n", "no": return false;
default: throw new Exception("please answer yes or no");
}
}




Re: NotNull Parser

2012-08-03 Thread Timon Gehr

On 08/03/2012 12:38 PM, Namespace wrote:

In context with my post here:
http://forum.dlang.org/thread/gajrorlwnrriljxnx...@forum.dlang.org#post-egvyqwkcqjglhrvujkar:40forum.dlang.org


I wrote the last days a NotNull Parser.
What is this?
The NotNull Parser generate for parameter statements with a
following "?" valid preconditions.

Example:
[code]
void foo(Object? o) {
// do something with o
}
[/code]

will convert into


The notation 'T?' is normally used for a nullable type.


Re: Return doesn't really return

2012-08-04 Thread Timon Gehr

On 08/04/2012 06:23 PM, Jacob Carlborg wrote:

I have a piece of code that looks like this:

https://github.com/jacob-carlborg/dstep/blob/master/clang/Visitor.d#L168

If I change that "first" function to look like this:

@property ParamCursor first ()
{
assert(any, "Cannot get the first parameter of an empty parameter list");

foreach (c ; this)
return c;

assert(0);
}

Then the last assert is hit. The return statement ends the foreach-loop
but it doesn't return from the function. I have not been able to create
a small test case for this.

Have I done a mistake somewhere or is this a bug in DMD?

Mac OS X, DMD 2.059 or 2.060.



int opApply (Delegate dg)
{
auto result = clang_visitChildren(cursor, 
&visitorFunction,cast(CXClientData) &dg);
return result == CXChildVisitResult.CXChildVisit_Break ? 1 : 0; // 
culprit

}


Re: Return doesn't really return

2012-08-04 Thread Timon Gehr

On 08/04/2012 08:54 PM, Jacob Carlborg wrote:

On 2012-08-04 19:08, Timon Gehr wrote:


int opApply (Delegate dg)
{
auto result = clang_visitChildren(cursor,
&visitorFunction,cast(CXClientData) &dg);
return result == CXChildVisitResult.CXChildVisit_Break ? 1 : 0; // culprit
}


Yes, right. I forgot about that. The Clang API doesn't really have a way
to represent the difference between "break" and "return" in D. The Clang
API works like this:

* Return 0 - Stop visiting children
* Return 1 - Continue visiting children
* Return 2 - Recursively visit the children

It doesn't really seem to be a way to map the difference between the
break and return codes that D uses to the Clang API.

Anyone got an idea for a workaround


bugfix.


or should I just continue to use "break" and never use "return"?



Return the exit code by reference:
Pass a tuple of delegate and return value to the visitorFunction per
the CXClientData pointer and make the visitorFunction store the exit 
code inside the return code field. Then return that from opApply.


Re: How to use "read_bool"?

2012-08-06 Thread Timon Gehr

On 08/04/2012 03:01 AM, Zeh wrote:

Thanks for the help, but i tryed both solutions posted and still not
working. :/

I get erros to compile the code posted by simendsjo. I try modify at my
own, but without success. The code suggest by Timon Gehr compiles, but
not work.



Works for me. Maybe readln behaves differently on windows?


Re: Why __traits(compile,...) fails here?

2012-08-08 Thread Timon Gehr

On 08/07/2012 03:52 PM, Philippe Sigaud wrote:

On Tue, Aug 7, 2012 at 12:42 PM, Zhenya  wrote:


Template alias parameters do not accept built-in types.


The trick is:

- A template type parameter (like (T)) recognizes types
- A template alias parameter(like (alias a)) recognizes names, symbols.

A built-in type is 'purely' a type. It's a keyword, and hence it's not
a symbol ('int' cannot be a D identifier)
A user-defined type is *both* a type and a symbol (because it has a name)
...


Yes, but note that this distinction does not make any sense.

alias int Int; // works

isType!Int // 'Int' is clearly a symbol, yet the instantiation fails.

alias declarations should just accept built-in types. If someone for
some obscure reason needs to exclude them, template constraints are
good enough. There is no reason to make built-in types behave specially
here.



Re: overloading a function taking a void[][]

2012-08-08 Thread Timon Gehr

Try this:

template digest(Hash) if(isDigest!Hash){
	digestType!Hash digest(Range)(Range data) if(!is(Range:void[][]) && 
isInputRange!Range && 
__traits(compiles,digest!Hash(ElementType!(Range).init))){

//implementation detail
}
	digestType!Hash digest()(scope const(void[])[] data...){ // templated 
as a workaround

//implementation detail
}
// ... (maybe more overloads)
}


Re: overloading a function taking a void[][]

2012-08-08 Thread Timon Gehr

On 08/08/2012 09:11 PM, Johannes Pfau wrote:

Am Wed, 08 Aug 2012 18:53:05 +0200
schrieb Timon Gehr:


Try this:

template digest(Hash) if(isDigest!Hash){
digestType!Hash digest(Range)(Range data)
if(!is(Range:void[][])&&  isInputRange!Range&&
__traits(compiles,digest!Hash(ElementType!(Range).init))){
//implementation detail
}
digestType!Hash digest()(scope const(void[])[] data...){ //
templated as a workaround
//implementation detail
}
  // ... (maybe more overloads)
}


Clever, but doesn't seem to work.  I can't create an instance of it, even
when explicitly specifying the types.



Well, I have done similar things in the past. The general concept should 
work.



BTW: This is a working version, but it does cause template bloat:
http://dpaste.dzfl.pl/d42a58aa



Maybe this helps:
http://dpaste.dzfl.pl/ed2e8e5d


Re: Convert little imperative code to functional coding style

2012-08-10 Thread Timon Gehr

Is this what you are looking for?

import std.stdio;
import std.range: iota;
import std.algorithm: map, filter, joiner;
import std.typecons : tuple;
import std.math : sqrt, floor;

void main(){
immutable limit = cast(size_t)floor(sqrt(1_000.0));

auto r = iota(2,limit).map!(m=>iota(1,m-1).map!(n=>tuple(m,n))).joiner
.filter!(t=>2*t[0]*(t[0]+t[1])==1_000)
.map!(t=>(t[0]^^4-t[1]^^4)*(2*t[0]*t[1]));

writeln(r.front);
}



Re: Optional extra return value? Multiple return values with auto?

2012-08-11 Thread Timon Gehr

There is no compiler bug. You cannot pass immutable/rvalue by reference
to mutable.


Re: Specialize mixin templates

2012-08-11 Thread Timon Gehr

On 08/11/2012 11:42 PM, Henning Pohl wrote:

A struct takes a mixin template as argument:

struct S(alias Mixin) {
mixin Mixin;
}


How to specialize a mixin template like this one to pass to S?

mixin template MixinTemplate(T) {
}


S(MixinTemplate!float); // Something like this


This is a way to do it:

struct S(alias Mixin){
mixin Mixin;
}

mixin template MixinTemplate(T){
}
mixin template MixinTemplateFloat(){
mixin MixinTemplate!float;
}

S!MixinTemplateFloat s;


Re: Iterating through enumeration

2012-08-12 Thread Timon Gehr

On 08/12/2012 01:54 PM, bearophile wrote:

Era Scarecrow:


But that problem goes away if you turn it into a small array right?
(And pass the array to the foreach to cycle over) So throwing that
idea out there you get...

foo[] array;

foreach(m; std.traits.EnumMembers!foo)
array ~= m;

foreach(m; array) {
//not compiler-time expansion like above
}


Often better (but every time builds an array on the heap):

foreach (m; [EnumMembers!Foo]) { // Not a static foreach
}

Bye,
bearophile


This builds the array once at compile time:

static immutable members = [EnumMembers!Foo];
foreach(m; members){

}


Re: Convert little imperative code to functional coding style

2012-08-12 Thread Timon Gehr

On 08/10/2012 09:59 PM, Nathan M. Swan wrote:

On Friday, 10 August 2012 at 18:26:56 UTC, Timon Gehr wrote:

Is this what you are looking for?

import std.stdio;
import std.range : iota;
import std.algorithm : map, filter, joiner;
import std.typecons : tuple;
import std.math : sqrt, floor;

void main(){
immutable limit = cast(size_t)floor(sqrt(1_000.0));

auto r = iota(2,limit).map!(m=>iota(1,m-1).map!(n=>tuple(m,n))).joiner
.filter!(t=>2*t[0]*(t[0]+t[1])==1_000)
.map!(t=>(t[0]^^4-t[1]^^4)*(2*t[0]*t[1]));

writeln(r.front);
}


Ugh! I guess functional isn't always the best ;)



In an attempt to destroy that guess I have uncovered the following
compiler bug: http://d.puremagic.com/issues/show_bug.cgi?id=8542


Re: char ***argc problems.

2012-08-12 Thread Timon Gehr

On 08/12/2012 10:33 PM, Andrew wrote:

I'm attempting to create a wrapper for MPI, however, MPI_Init
wants to read the arguments for main():

MPI_Init(int *argv, char ***argc);

How do I get this last level of pointer reference?

So far, I have:

void main (string[] args)
{
auto argarr = new char*[args.length];
foreach(i, a; args)
argarr[i] = (a.dup ~ '\0').ptr;

int argc = to!(int)(argarr.length);
MPI_Init(&argc, argarr.ptr);
}

Any ideas?

-Andrew


Maybe like this?

import std.algorithm, std.array, std.conv;
void main(string[] args){
auto argarr = args.map!(a=>(a ~ '\0').ptr).array;

int argc = to!(int)(argarr.length);
auto argv = argarr.ptr;

MPI_Init(&argc, &argv);

args = argv[0..argc].map!(to!string).array;

// ...
}


Re: char ***argc problems.

2012-08-12 Thread Timon Gehr

On 08/12/2012 11:38 PM, Andrew wrote:

On Sunday, 12 August 2012 at 20:57:34 UTC, Timon Gehr wrote:

On 08/12/2012 10:33 PM, Andrew wrote:

I'm attempting to create a wrapper for MPI, however, MPI_Init
wants to read the arguments for main():

MPI_Init(int *argv, char ***argc);

How do I get this last level of pointer reference?

So far, I have:

void main (string[] args)
{
   auto argarr = new char*[args.length];
   foreach(i, a; args)
   argarr[i] = (a.dup ~ '\0').ptr;

   int argc = to!(int)(argarr.length);
   MPI_Init(&argc, argarr.ptr);
}

Any ideas?

-Andrew


Maybe like this?

import std.algorithm, std.array, std.conv;
void main(string[] args){
auto argarr = args.map!(a=>(a ~ '\0').ptr).array;

int argc = to!(int)(argarr.length);
auto argv = argarr.ptr;

MPI_Init(&argc, &argv);

args = argv[0..argc].map!(to!string).array;

// ...
}


I don't know why I didn't think of this:

auto argv = argarr.ptr;

Which fixed it.

Unfortunately, using args.map! doesn't work, because it returns
an immutable, which MPI_Init can't take.



oops.
auto argarr = args.map!(a=>(a.dup ~ '\0').ptr).array;


Thanks for the help

-Andrew





Re: Sudoku Py / C++11 / D?

2012-08-15 Thread Timon Gehr

On 08/15/2012 12:31 AM, bearophile wrote:

http://www.reddit.com/r/cpp/comments/y6gwk/norvigs_python_sudoku_solver_ported_to_c11/


http://nonchalantlytyped.net/blog/2012/08/13/sudoku-solver-in-c11/

His C++11 port is 316 lines long:
https://gist.github.com/3345676

How many lines for a (not golfed) D translation of the original Python
code?

Bye,
bearophile


Probably not what you want, but solves sudoku quite well:
dpaste.dzfl.pl/69669b05


Re: Sudoku Py / C++11 / D?

2012-08-15 Thread Timon Gehr

On 08/16/2012 03:56 AM, maarten van damme wrote:

solving sudoku's well too : http://dpaste.dzfl.pl/903e34b5
I have one question though, how can you make it find all possible solutions?



Keep on backtracking when you find one until there are no more
possibilities to explore. (i.e. get rid of the return value of 'fill')


Re: Matrix Multiplication benchmark

2012-08-16 Thread Timon Gehr

On 08/16/2012 03:15 PM, Matthias Pleh wrote:

I've created a simple 4x4 Matrix struct and have made some tests, with
surprising results. (although I've heard from similar results in c++)

struct mat4 {
  float[4][4] m;
  mat4 opMul(in mat4 _m);
}
mat4 mul(in mat4 m1, in mat4 m2);


I've tested this 2 multiplication functions (overloaded and free).

Result (100_000 times, windows7 64bit, 32bit build):

DMD: (dmd -O -inline -release)
opMul: 20 msecs
mul : 1355 msecs

GDC: (gdc -m32 -O3 -frelease)
opMul: 10 msecs
mul : 1481 msecs


Why this huge difference in performance?


Note that you have missed to provide the full benchmark code listing.


Re: Sudoku Py / C++11 / D?

2012-08-16 Thread Timon Gehr

On 08/16/2012 09:52 PM, maarten van damme wrote:

I've now ran in something odd. Using a slight variant from my program on
dpaste (can't upload modified version atm but changes are minimal) it
takes 0.6 seconds to solve the hard puzzle the python version took 180
seconds for.


This is because the python version happened to choose an unlucky search
order. Sudoku is NP-complete after all, so it is not surprising that
programs have a bad worst case run time.


Yet on the last puzzle, the impossible one, python takes
1800 seconds to figure out it's impossible yet mine takes over 3885
seconds. Where is this slowdown coming from?



This is because your specific solution is slow.

Mine takes <20ms on the 'hard' puzzle and ~13s on the impossible one.
(~2.4 GHZ intel x86_64 machine, with gdmd -O -release -inline 
-noboundscheck.)

There is a constant factor between those two solutions.


Re: Sudoku Py / C++11 / D?

2012-08-16 Thread Timon Gehr

On 08/16/2012 11:51 PM, maarten van damme wrote:


 > This is because your specific solution is slow.
 >
 > Mine takes <20ms on the 'hard' puzzle and ~13s on the impossible one.
 > (~2.4 GHZ intel x86_64 machine, with gdmd -O -release -inline
-noboundscheck.)
 > There is a constant factor between those two solutions.

I've compiled it using dmd on my latitude e5500 which is not that fast
so I don't think it's that slow...



Compiled and run in the same environment, your solution takes 0.26s on
the 'hard' one, whereas mine takes 0.0013s. Your solution takes ~1600s
on the impossible one whereas mine takes ~13s.


Besides, lets say mine is five times slower,


Hard facts say that it is at around 100x-200x slower.


3000 seconds is still waaay  to much.


Sounds reasonable to me.


When I'm back able to get my laptop to use my crapy data
connection I'll compare.

Do you have some optimization ideas by the way?



First of all, getting rid of the dynamic allocations is low hanging fruit.

Then you'll have to reduce the number of times you recompute the same
information. Update/restore the possibilities array as you
update/restore the solution attempts. Do this for the whole board at
once and use a compact representation of possibilities.


Re: Sudoku Py / C++11 / D?

2012-08-16 Thread Timon Gehr

On 08/17/2012 01:13 AM, maarten van damme wrote:

great, going to play around with it tomorrow.
Caching the possibilities is going to look really ugly but you're
right, it's going to give quiet a boost in performance.

I'm also going to format your source code a bit more and see if I can
follow it's logic as it seems to be way more efficient. (although
compilation is failing here, I'm running dmd 2.059 and it gives "can't
stride on chunks!(short))


Works for me both with DMD 2.060 and GDC with the 2.059 front end.



would using short or bytes increase performance compared to integers?


Using less memory sometimes increases performance, but here it is not 
significant.



if so, why did you use shorts instead of bytes?


Because I need 9 bits per entry to keep track of all the combinations
of possibilities.


Re: How create a operator tree?

2012-08-17 Thread Timon Gehr

On 08/17/2012 10:38 AM, Namespace wrote:

o_O
I was hoping that there is a shorter way than this.


I hacked together the following little parser (not extensively tested).

http://dpaste.dzfl.pl/e616692e

It transforms the input expression into polish notation, ignoring space
characters.
Note that it is significantly shorter than the regex attempt.

It handles numbers, unary +, -, binary +, -, *, /, ^, where ^
associates to the right, as well as nested parentheses. It should be
trivial to extend. (in this case you might want to generate the switch
cases automatically from the operator precedence table.)


Re: How create a operator tree?

2012-08-17 Thread Timon Gehr

On 08/17/2012 02:55 PM, Timon Gehr wrote:

On 08/17/2012 10:38 AM, Namespace wrote:

o_O
I was hoping that there is a shorter way than this.


I hacked together the following little parser (not extensively tested).

http://dpaste.dzfl.pl/e616692e

It transforms the input expression into polish notation, ignoring space
characters.
Note that it is significantly shorter than the regex attempt.

It handles numbers, unary +, -, binary +, -, *, /, ^, where ^
associates to the right, as well as nested parentheses. It should be
trivial to extend. (in this case you might want to generate the switch
cases automatically from the operator precedence table.)


(the first while loop is superfluous)


Re: Non-immutable char[] doesn't change?

2012-08-18 Thread Timon Gehr

On 08/18/2012 02:15 PM, Salih Dincer wrote:

This may be the solution...:)

char[] b = cast(char[])"abc".dup; // ok, unique reference

Sorry...


You don't need the cast in this case.

Topic: It is not a bug, but it might be surprising because the
behaviour of typeid is different with polymorphic types.

Typeid on a class object gives you back the RTTI structure of the
value's type, while typeid on anything else gives you back the RTTI
of the statically determined variable type.

The reason this works this way is because class objects are the only
objects which actually carry runtime type information with them.


Re: Sudoku Py / C++11 / D?

2012-08-20 Thread Timon Gehr

On 08/20/2012 10:43 PM, maarten van damme wrote:


Still it comes nowhere near beating timons solution. Is the logic of
that documented somewhere because I don't understand it.



Try this:
http://dpaste.dzfl.pl/23b1b6e2


Re: template and constraints

2012-08-20 Thread Timon Gehr

On 08/20/2012 11:52 PM, bioinfornatics wrote:

I got a little problem with these code:


double div(T a, U b)() if( a > 0 && b > 0 ){ // not works T and U unknwn
identifier
 return a / b;
}
double div(T,U)(T a, U b) if( a > 0 && b > 0 ){ // not works, a  and b
not known at compile time
 return a / b;
}

double div(double a, double b)() if( a > 0 && b > 0 ){ // works but not
generic
 return a / b;
}
_


The only one who works is a not generic! they are a way? or i need to
write for each parameter type?



Alias parameters. auto div(alias a, alias b)().


Re: reduce!"a+b"(R) syntax question

2012-08-21 Thread Timon Gehr

On 08/21/2012 07:05 PM, Andrew Spott wrote:

When I'm doing an anonymous function for something like reduce,
how are the arguments determined?  Is it alphabetical?  Can I use
any names (reduce!"d-c"(R)?), or are the names defined in the
function "reduce"?


They are defined here:
http://dlang.org/phobos/std_functional.html#binaryFun



This syntax isn't really documented at all in the language
reference, which makes it a little bit of guess work.



This is not part of the language, it is a library artefact:
http://dlang.org/phobos/std_algorithm.html

'Many functions in this module are parameterized with a function or a 
predicate. The predicate may be passed either as a function name, a 
delegate name, a functor name, or a compile-time string. The string may 
consist of any legal D expression that uses the symbol a (for unary 
functions) or the symbols a and b (for binary functions). These names 
will NOT interfere with other homonym symbols in user code because they 
are evaluated in a different context. The default for all binary 
comparison predicates is "a == b" for unordered operations and "a < b" 
for ordered operations.'


Re: Sudoku Py / C++11 / D?

2012-08-21 Thread Timon Gehr

On 08/21/2012 05:52 PM, maarten van damme wrote:
> On 08/20/2012 11:49 PM, Timon Gehr wrote:> On 08/20/2012 10:43 PM, 

maarten van damme wrote:


Still it comes nowhere near beating timons solution. Is the logic of
that documented somewhere because I don't understand it.



Try this:
http://dpaste.dzfl.pl/23b1b6e2


Thank you very much, this makes everything more clearer. I'm not very
familiar with binary operators so the comments help out a lot.
Would you mind it if I shamelessly copy your solution of using shorts
to store possibilities in?



Not at all.


I'm also a bit confused. How come the int's you change from a square
passed from squ are stilled referenced to the original array? I
thought it lost that reference as soon as you did any operations (like
concenating) on it?



The used ranges just express patterns of iteration. They replace manual
for-loops. The data source has assignable elements, and the relevant
range operations in Phobos all propagate this capability to their
result.



Re: inout functions

2012-08-23 Thread Timon Gehr

On 08/24/2012 12:14 AM, Piotr Szturmaj wrote:

Hi,

I found this code of std.range.iota's Result struct:

 @property inout(Value) front() inout { assert(!empty); return
current; }

What's the purpose of inout on parameterless functions?


It is a method of a struct, therefore it is not parameterless, but has
a hidden parameter. 'inout' qualifies the implicit 'this' reference.
Inside the method body, typeof(this) is inout(Result).



Re: struct init property

2012-08-24 Thread Timon Gehr

On 08/24/2012 09:39 AM, nocide wrote:

Am 23.08.2012 19:15, schrieb nocide:

struct has no default constructor and instances are initialized with the
init property.
Can I declare or override the init property for a custom defined struct?



Ok, the initializer forks fine for me,
but I've encounterd following situation: (simplified code)

// This compile fine
struct Foo {
 union {
 struct {
 int a = 1, b = 2, c = 3, d = 4;
 }
 float[4] e;
 }
}


// but this doesn't compile
struct Foo {
 union {
 struct {
 int a, b, c, d;
 }
 float[4] e = [ 1.0f, 2.0f, 3.0f, 4.0f ];
 }
}
Foo f;  // Error: struct main.Foo overlapping initialization for struct


Is this a bug?




Yes.


Re: Sudoku Py / C++11 / D?

2012-08-24 Thread Timon Gehr

On 08/24/2012 09:32 PM, maarten van damme wrote:

I've distiled what I understood from your source and the resulting
executable managed to solve the impossible one in 27 seconds while
your source takes 41 seconds.



It is 10s vs 13s with GDC on my machine.



Re: Check for ctfe

2012-08-24 Thread Timon Gehr

On 08/25/2012 02:06 AM, cal wrote:

I saw something on the forum not too long ago about statically checking
to see if the current function is being executed at compile time, but
can't seem to find it now. Can it be done? (Like static if (__ctfe__) or
something)


if(__ctfe)


Re: Check for ctfe

2012-08-24 Thread Timon Gehr

On 08/25/2012 02:15 AM, bearophile wrote:

cal:


I saw something on the forum not too long ago about statically
checking to see if the current function is being executed at compile
time, but can't seem to find it now. Can it be done? (Like static if
(__ctfe__) or something)


It's named __ctfe, but unfortunately it's an (immutable) run-time value.
When you use it you rely on the dead code elimination optimization done
by the compiler.

Bye,
bearophile


Which is basically guaranteed to be performed.




Re: Sudoku Py / C++11 / D?

2012-08-24 Thread Timon Gehr

On 08/25/2012 01:01 AM, Timon Gehr wrote:

On 08/24/2012 09:32 PM, maarten van damme wrote:

I've distiled what I understood from your source and the resulting
executable managed to solve the impossible one in 27 seconds while
your source takes 41 seconds.



It is 10s vs 13s with GDC on my machine.



I have inlined some ranges.

http://dpaste.dzfl.pl/4a7e4038

I now measure 10.5s vs 6.7s (GDC) and 20s vs 12s (DMD).


Re: Sudoku Py / C++11 / D?

2012-08-24 Thread Timon Gehr

On 08/25/2012 02:38 AM, Timon Gehr wrote:

On 08/25/2012 01:01 AM, Timon Gehr wrote:

On 08/24/2012 09:32 PM, maarten van damme wrote:

I've distiled what I understood from your source and the resulting
executable managed to solve the impossible one in 27 seconds while
your source takes 41 seconds.



It is 10s vs 13s with GDC on my machine.



I have inlined some ranges.

http://dpaste.dzfl.pl/4a7e4038

I now measure 10.5s vs 6.7s (GDC) and 20s vs 12s (DMD).


I meant to paste this: http://dpaste.dzfl.pl/8fa23a97


Re: Sudoku Py / C++11 / D?

2012-08-24 Thread Timon Gehr

On 08/25/2012 02:51 AM, Chris Cain wrote:

On Friday, 24 August 2012 at 23:14:02 UTC, maarten van damme wrote:

http://en.wikipedia.org/wiki/File:Sudoku_puzzle_hard_for_brute_force.jpg


It occurs to me that one of the main reasons why this particular puzzle
would be hard for brute force is that the first line is blank and more
than half of the second line is blank, and it seems like it is designed
to have as many choices as possible before a set square is encountered.

I bet it could be solved much quicker by a computer by doing it in reverse.

I've got some ideas, maybe I'll write a solution to this myself. :)


FWIW both mine and Maarten's solution require a trivial amount of time
to solve it.


Re: Check for ctfe

2012-08-25 Thread Timon Gehr

On 08/25/2012 12:53 PM, Minas Mina wrote:

Why is it "if( __ctfe )" and not
static if.. ?


Both branches need to be compiled in order to have both a ctfe and a
runtime version.


Re: Reading bytes and converting to int

2012-08-26 Thread Timon Gehr

On 08/26/2012 04:19 PM, Tommi wrote:

On Saturday, 25 August 2012 at 20:58:47 UTC, Jonathan M Davis wrote:

auto buf = file.rawRead(new ubyte[](4));


Could we somehow skip making the temporary buffer, and read from the
file directly into an existing variable. Can we make a slice of one
element that points to an existing value.

import std.stdio;

struct BigValue // has no indirection
{
 int  m_value1;
 int  m_value2;
 long m_value3;
 // ...
}

BigValue g_bigValue;

void fun()
{
 auto file = File("filename");

 // How to create a slice of size 1 which references g_bigValue?
 BigValue[] refToBigValue /* = ? */ ;


auto refToBigValue = (&g_bigValue)[0..1];



 buffer = file.rawRead(refToBigValue);
}




Re: opUnary overloading

2012-08-26 Thread Timon Gehr

On 08/26/2012 10:33 PM, cal wrote:


I have a struct wrapping a union of an int and a float, and want to
overload opUnary for this struct:

struct Value
{
 enum Type {
 INT, FLOAT
 }

 Type type;

 union {
 int i;
 float f;
 }

 this(int _i) {
 i = _i;
 type = Type.INT;
 }

 this(float _f) {
 f = _f;
 type = Type.FLOAT;
 }

 auto opUnary(string s)() if (s == "-") {
 if (type == Type.INT)
 return -i;
 if (type == Type.FLOAT) // If i comment this out, I get an int
back
 return -f;  // as expected
 assert(0);
 }
}

Value v1 = Value(25);
assert(v1.type == Value.Type.INT);
auto neg = -v1;
writeln(typeof(neg).stringof); // this returns float, when it should
return int

The part I don't understand is this: in the opUnary method, if I comment
out the second if conditional (if (type == Type.FLOAT)) then when doing
the negation on v1 I get an INT as expected. If I don't comment this
code out, I get a float.

When commented out, I get back -25 as an int, which i expect. When not
commented out, I get back -nan, which suggests to me that it is
returning the (uninitialized) float from the union, not simply giving me
back the int as a float.

Could someone explain this?





Compiler bug.

http://d.puremagic.com/issues/

Also see:
http://d.puremagic.com/issues/show_bug.cgi?id=8307

I assume the compiler fails to add an implicit conversion node into the
AST because at the point where -i is returned, the return type is still
assumed to be 'int'. What you are observing is not type coercion, but
an x87 FPU stack underflow.




Re: float[] → Vertex[] – decreases performance by 1000%

2012-08-28 Thread Timon Gehr

On 08/28/2012 06:35 PM, David wrote:

Am 28.08.2012 17:41, schrieb bearophile:

David:


The arrays are 100% identical (I dumped a Vertex()-array and a raw
float-array, they were 100% identical).


I hope some people are realizing how much time is being wasted in this
thread. Taking a look at the asm is my suggestion still. If someone is
rusty in asm, it's time to brush away the rust with a steel brush.

Bye,
bearophile


You're right, but I also said, that I don't care anylonger, I found a
workaround, I can live with it. I generally tend to ignore dmd bugs and
just workaround them, I don't have the time to track down every stuipid
bug from a ~8k codebase.

Thanks anyways for your help.


Use this to create a minimal test case with minimal user interaction:
https://github.com/CyberShadow/DustMite


Re: float[] → Vertex[] – decreases performance by 1000%

2012-08-28 Thread Timon Gehr

On 08/29/2012 01:26 AM, David wrote:

Use this to create a minimal test case with minimal user interaction:
https://github.com/CyberShadow/DustMite


Doesn't help if dmd doesn't crash, or?



It doesn't help a lot if compilation succeeds, but you stated that you
generally tend to ignore dmd bugs. Most dmd bugs make compilation fail.


Re: Call a function on an entire slice

2012-08-29 Thread Timon Gehr

On 08/29/2012 03:38 PM, monarch_dodra wrote:

D provides ways to operate on an entire (sub) slice:
int[] a = ... ;
a[] *= 5; //Multiply everything by 5.
a[0 .. 2] = 3; //Set indexes 0 to 1 to the value 3.

I was wondering if there was any way to do this for a specified function?


struct S
{
 void foo()
 {
 writeln("foo");
 }
}

void bar(S s)
{
 writeln("bar");
}

void main()
{
   S[5] a;
   a[].foo(); //undefined identifier 'foo'
   a[].bar(); //cannot implicitly convert expression (a[]) of type S[] to S
};

I know I can just foreach it, but it doesn't quite have the same
expressive power.



Yes it does.


If the built in arithmetic types have this power, why not functions?


Because the built-in arithmetic vector operators are supported by hardware.


Re: Assigning global and static associative arrays

2012-09-02 Thread Timon Gehr

On 09/02/2012 03:45 PM, monarch_dodra wrote:

On Saturday, 1 September 2012 at 09:16:30 UTC, Jonathan M Davis
wrote:

[SNIP]
so it looks like not only do all instances of the same string enum use
the
same memory, but another enum with the same string literal shares it
as well.
So, only one is allocated. And on Linux at least, as I understand it, the
string literals go in ROM. But it may be that the above code functions
differently in Windows, since it _doesn't_ put string literals in ROM.
[SNIP]


FYI: I get the exact same behavior in Windows. Not that it
matters, but it sounded like you were asking.

I'm a bit confused now though: Why would someone want to use an
enum when they could use a static immutable instead?

If I understood correctly, the enum will *always* be inlined
(doesn't create any actual symbols). But if you use a static
immutable, then the compiler will create an actual symbol, but
probably inline it away if it judges that is a better choice
anyways...

Is there *any* scenario where one would choose the enum over the
static immutable...?


- If there is no need to access it at run time.
- Type deduction.


Re: Assigning global and static associative arrays

2012-09-02 Thread Timon Gehr

On 09/02/2012 06:26 PM, monarch_dodra wrote:

On Sunday, 2 September 2012 at 16:20:16 UTC, Timon Gehr wrote:

On 09/02/2012 03:45 PM, monarch_dodra wrote:


FYI: I get the exact same behavior in Windows. Not that it
matters, but it sounded like you were asking.

I'm a bit confused now though: Why would someone want to use an
enum when they could use a static immutable instead?

If I understood correctly, the enum will *always* be inlined
(doesn't create any actual symbols). But if you use a static
immutable, then the compiler will create an actual symbol, but
probably inline it away if it judges that is a better choice
anyways...

Is there *any* scenario where one would choose the enum over the
static immutable...?


- If there is no need to access it at run time.
- Type deduction.


-Type deduction: Not really, I can just declare it as "immutable auto".


enum x = 2;

void main(){
auto y = x;
y = 3;
}



-no need to access it at run time. I guess.




Re: typeof(enum)

2012-09-07 Thread Timon Gehr

Accidentally replied to your private email first.

On 09/08/2012 12:55 AM, Minas wrote:

import std.stdio;

enum PI = 3.14;

void main()
{
 writeln(typeid(typeof(PI)));
}

It prints "double". Shouldn't it be immutable(double).


No.

auto x = PI;
x++;


I think it would  make more sense, as it is a constant.


It never makes sense to have mutable values, but their type may still 
allow mutation of variables of that type.



Plus, it could be shared among threads.


The symbol PI does not exist at runtime.


Re: int[3][4]*

2012-09-07 Thread Timon Gehr

On 09/08/2012 04:19 AM, bearophile wrote:

Ellery Newcomer:


alright what's the deal?


This is one of the "clean" ways to do it:

void main () {
 static struct Mat {
 int[3][4] m;
 alias m this;
 }
 Mat* fooz = new Mat;
 fooz[1][3] = 5;


This may corrupt your heap.


}


Bye,
bearophile


I prefer this:

void main(){
alias int[3][4] fooz;
int[3][4]* i = (new fooz[1]).ptr;
}

But I think the original example should just work.


Re: int[3][4]*

2012-09-08 Thread Timon Gehr

On 09/08/2012 01:21 PM, bearophile wrote:

Timon Gehr:


This may corrupt your heap.


I usually don't put the alis this...



I prefer this:

void main(){
alias int[3][4] fooz;
int[3][4]* i = (new fooz[1]).ptr;
}


This allocates past the size of the array, the information to append to
the array of fooz. It's a very little amount of memory.

Since some weeks, if you allocate a single struct that contains a single
fixed size array, that memory is not allocated.

Bye,
bearophile


Wasn't aware that this got fixed. Thanks!


Re: since when was this valid syntax?

2012-09-08 Thread Timon Gehr

On 09/08/2012 04:11 PM, Ellery Newcomer wrote:

alias enum int e;


It is valid according to the grammar and DMD ignores meaningless attributes.

scope shared @disable @trusted package final override deprecated extern 
__gshared synchronized pure nothrow ref static abstract immutable alias 
auto final override deprecated extern __gshared synchronized enum pure 
nothrow ref static abstract @safe @disable scope int e;


Re: since when was this valid syntax?

2012-09-08 Thread Timon Gehr

On 09/08/2012 06:44 PM, bearophile wrote:

Timon Gehr:


It is valid according to the grammar and DMD ignores meaningless
attributes.


Do you know why?


No reason.


Is it just a unfinished part of dmd, or Walter believes
this is an acceptable design for a compiler?


Jonathan would say he has more important things to do.


In years I have never heard a comment from him on this bad situation.



I'd design it differently as well. But this is the kind of thing that
can be ignored indefinitely without hurting the programmer more than
once. A similar issue is that the compiler actually won't detect
clashing function overloads, leaving the error report up to the linker.



Re: since when was this valid syntax?

2012-09-08 Thread Timon Gehr

On 09/08/2012 09:25 PM, Maxim Fomin wrote:

On Saturday, 8 September 2012 at 16:00:44 UTC, Timon Gehr wrote:

On 09/08/2012 04:11 PM, Ellery Newcomer wrote:

alias enum int e;


It is valid according to the grammar and DMD ignores meaningless
attributes.

scope shared @disable @trusted package final override deprecated
extern __gshared synchronized pure nothrow ref static abstract
immutable alias auto final override deprecated extern __gshared
synchronized enum pure nothrow ref static abstract @safe @disable
scope int e;


How dmd's parser is written if it allows such things?


It's the grammar that allows this. Every parser that follows the grammar 
would accept this.


Re: const attribute makes whole element const?

2012-09-08 Thread Timon Gehr

On 09/09/2012 01:16 AM, Namespace wrote:

Why fail this code?
without "const" on "Name" it works fine.

http://dpaste.dzfl.pl/9fa0986a


const fields cannot be written to. This includes the case when the
entire struct is written to at once.


Re: delegate from lambda expression

2012-09-09 Thread Timon Gehr

On 09/10/2012 01:55 AM, bearophile wrote:


Your code doesn't look good,


Yes it does.



Re: delegate from lambda expression

2012-09-09 Thread Timon Gehr

On 09/10/2012 01:20 AM, timotheecour wrote:

I'd like to achieve the following:

import std.stdio,std.range,std.algorithm,std.array;
void main(){
auto dg=a=>a*2;
auto a=iota(0,10);
writeln(a.map!dg.array);
}

but this doesn't compile:
Error: variable [...]dg type void is inferred from initializer delegate
(__T26 a)
{
return a * 2;
}
, and variables cannot be of type void

However this works:
writeln(a.map!(a=>a*2).array);
but I want to reuse dg in other expressions (and avoid repeating myself)
Also, I want to avoid using string litteral enum dg=`a*2` as in my case
dg is much more complicated and this is cleaner without a string IMHO.

My questions:
1) why can't the compiler infer the type int(int) for dg?


Because it can't. D unfortunately does not have powerful type inference.


2) how to convert a lambda a=>a*2 to a delegate or function?


Those need full type information. The lambda as shown is generic.


3) if 2 is not possible, how to achieve what I'm trying to do WITHOUT
having to make the type explicit as in "int delegate(int) dg=(int
a){return a*2;}"?


template ID(alias a){ alias a ID; }

void main(){
alias ID!(a=>a*2) dg;
auto a=iota(0,10);
writeln(a.map!dg.array);
}



4) is there a way to have template delegates, and what's the syntax in
this simple example?



Already shown.



Re: filter out compile error messages involving _error_

2012-09-09 Thread Timon Gehr

On 09/10/2012 01:52 AM, timotheecour wrote:

Can we filter out compiler errors involving _error_ as template parameter?
Clearly the error is coming from upstream so there's no need to even
show those.

eg:
Error: template mypackage.mymodule.myfunction cannot deduce template
function from argument types !()(_error_)



You can file all instances of this you can find as 'diagnostic' bugs.


Re: inconsistent behavior with implicit imports

2012-09-09 Thread Timon Gehr

On 09/10/2012 01:47 AM, timotheecour wrote:

This works:

import std.stdio;
void main(){
 writeln(std.conv.to!double(1));
}


This doesn't compile:

import std.stdio;
void main(){
 std.stdio.writeln(std.conv.to!double(1));
}

=>Error: undefined identifier std

So it seems for conv, import std.conv is not needed, but for writeln,
import std.stdio is needed. Why?



I assume because std.stdio imports std.conv, but not vice versa.


Also, I always get link errors when using those "implicit imports" for
my own modules and using "rdmd". Is there a way to allow this without
link errors in the following (using rdmd) ?

void main(){
 mypackage.mymodule.myfun(0);
}

which would behave as:

import mypackage.mymodule;
void main(){
 myfun(0);
}




This is a quirk of DMD, not a language feature.
You can file the implicit import behaviour as a bug.



Re: filter out compile error messages involving _error_

2012-09-09 Thread Timon Gehr

On 09/10/2012 02:14 AM, Jonathan M Davis wrote:

On Monday, September 10, 2012 01:52:52 timotheecour wrote:

Can we filter out compiler errors involving _error_ as template
parameter?
Clearly the error is coming from upstream so there's no need to
even show those.

eg:
Error: template mypackage.mymodule.myfunction cannot deduce
template function from argument types !()(_error_)


They're useful, because they give you the instantiation chain, and it makes it
clear why each instantiation is failing. Yes, what you ultimately need to fix
is what's resulting in _error_, but that doesn't mean that the rest is useless
(like knowing _where_ the template was instantiatied from and what arguments
were used to instantiate it). If you don't want to see those, then use

grep -v _error_

on the compiler's output.

- Jonathan M Davis



Don has expressed the desire to weed those out completely.


Re: delegate from lambda expression

2012-09-09 Thread Timon Gehr

On 09/10/2012 02:56 AM, bearophile wrote:

timotheecour:


What was wrong with it and what would you suggest to improve it?


Nothing serious, I just suggest to give a bit more air to your code,
adding a space around operators, after commas, etc. Otherwise your code
risk looking like Timon's code ;-)



Which is usually extremely beautiful. This is not a liability.


I have also compiled the code with -property. Some people don't like
this. The choice is yours, but you need to express an informed choice.



Will the way I'm skipping "()" ever be deprecated?


Who knows. People disagree on this :-)



(That means it is here to stay.)




One of the points of UFCS was to avoid writing too much parentheses


Where did you read this?



He most definitely has a point there.



Re: const attribute makes whole element const?

2012-09-09 Thread Timon Gehr

On 09/10/2012 02:05 AM, Namespace wrote:

I had never problems with that in C++.


clang++ sez:
error: cannot define the implicit default assignment operator for 'S', 
because non-static const member 'x' can't use default assignment operator



If I have members which are const because they are assigned only one
time and needs no other assignment, why should I declare this member not
as const?



You can, but then you have to provide your own assignment operator and
you have to work around the aforementioned bug that implies the
assignment operator is not invoked for associative array index
assignments.


In the example I know exactly that I assign only one time a name to this
struct, so why I should not declare it as const?

Other example: you have a unique birthday date. This is const you cannot
change it like a name or a telephone number.


Therefore I cannot be default-assigned to.




Re: since when was this valid syntax?

2012-09-10 Thread Timon Gehr

On 09/10/2012 07:07 AM, Ellery Newcomer wrote:

On 09/08/2012 09:01 AM, Timon Gehr wrote:

On 09/08/2012 04:11 PM, Ellery Newcomer wrote:

alias enum int e;


It is valid according to the grammar


I don't believe you. Show me the derivation.



The grammar as shown on dlang.org indeed seems not to allow this, but
it is out of date as it also wouldn't allow

alias extern(C) void function() fun;




Re: auto limitation?

2012-09-11 Thread Timon Gehr

On 09/11/2012 08:57 PM, Maxim Fomin wrote:


I think it is UB rather than a bug.


No, this is a bug.


The spec says that return types must match exactly.


Exactly. If it was UB, the spec would say the behaviour is undefined if 
they don't match exactly.




AFAIK auto is a feature to infer return type, not to
magically adjust to multiple incompatible types.



Re: auto limitation?

2012-09-11 Thread Timon Gehr

On 09/11/2012 09:29 PM, Namespace wrote:

On Tuesday, 11 September 2012 at 19:27:40 UTC, Timon Gehr wrote:

On 09/11/2012 08:57 PM, Maxim Fomin wrote:


I think it is UB rather than a bug.


No, this is a bug.


The spec says that return types must match exactly.


Exactly. If it was UB, the spec would say the behaviour is undefined
if they don't match exactly.



AFAIK auto is a feature to infer return type, not to
magically adjust to multiple incompatible types.


So what? Should my code work or not?


According to the spec it should fail compilation.


Re: access enclosing type from shared static this()

2012-09-19 Thread Timon Gehr

On 09/19/2012 09:37 PM, "Øivind" wrote:

I want to access the type of the enclosing struct in in a shared static
initializer.. How do I do that? The following code will not compile:

mixin template MsgMixin(T ...) {
   static string getName(this M)() {
 return M.stringof;
   }
   shared static this() {
 import std.stdio;
 writeln("register " ~ getName());
   }
}

struct MsgTestMsg {
   mixin MsgMixin!();
}

I get the following error messages:

src/main.d(40): Error: template main.MsgTestMsg.MsgMixin!().getName does
not match any function template declaration
src/main.d(40): Error: template main.MsgTestMsg.MsgMixin!().getName(this
M) cannot deduce template function from argument types !()()

If not possible, just getting the name of the enclosing struct would
help a lot!

-Øivind



use typeof(this), eg:

mixin template MsgMixin(T ...) {
shared static this() {
import std.stdio;
writeln("register " ~ typeof(this).stringof);
}
}



Re: tuple(tuple(1)) fails to compile, but tuple(tuple(1),1) works

2012-09-20 Thread Timon Gehr

On 09/21/2012 01:04 AM, timotheecour wrote:

inconsistent:
auto a1=tuple(tuple(1));//CT error
auto a2=tuple(tuple(1),1);//works

bug?


Yes. In general, if there is a compile time error other than a static
assertion failure that points to Phobos code, you can assume that it is
a library bug.


Re: function is not function

2012-09-21 Thread Timon Gehr

On 09/21/2012 10:41 PM, Ellery Newcomer wrote:

On 09/21/2012 01:17 PM, bearophile wrote:

pragma(msg, is(typeof(a) == function)); // nope!


code in pyd suggests this evaluated to true once upon a time.



I don't think it ever did. It is just very easy to get wrong.


Re: Testing for template argument being result of takeExactly

2012-09-23 Thread Timon Gehr

On 09/23/2012 01:54 AM, Jonathan M Davis wrote:

I'm trying to test whether a template argument is the type returned by
takeExactly, and I haven't been able to sort out the template voodoo required
yet.  It would be a lot easier if I had a variable to work with, but I just
have the type, and the fancy is expression required to pull it off is fancy
enough that I haven't been able to sort it out yet. At present, I have this:

import std.range;
import std.stdio;

template Hello(R)
 if(is(R r == U, V, V w, U = typeof(takeExactly(w, 1
{
 alias R Hello;
}

void main()
{
 auto str = "hello";
 auto t = takeExactly(str, 3);
 writeln(t);
 Hello!(typeof(t)) h = t;
 writeln(h);
}


I need Hello to instatiate if R is the type returned by takeExactly and fail
to instantiate otherwise. At present, the code gives these compilation errors:

q.d(15): Error: template instance Hello!(Result) Hello!(Result) does not match
template declaration Hello(R) if (is(R r == U,V,V w,U =
typeof(takeExactly(w,1
q.d(15): Error: Hello!(Result) is used as a type
q.d(16): Error: template std.stdio.writeln does not match any function
template declaration
q.d(16): Error: template std.stdio.writeln(T...) cannot deduce template
function from argument types !()(_error_)

So, clearly I don't have the is expression right, and this is seriously
pushing the edge of my knowledge of is expressions. So, any help would be
appreciated. Thanks.

- Jonathan M Davis



import std.range, std.traits;
import std.stdio;
template Hello(R) if(is(typeof(R._input.takeExactly(2)) == R)){
alias R Hello;
}

void main(){
auto str = "hello";
auto t = takeExactly(str, 3);
writeln(t);
Hello!(typeof(t)) h = t;
writeln(h);
}


Re: Testing for template argument being result of takeExactly

2012-09-23 Thread Timon Gehr

On 09/23/2012 03:48 PM, Andrei Alexandrescu wrote:

On 9/23/12 8:47 AM, Timon Gehr wrote:

import std.range, std.traits;
import std.stdio;
template Hello(R) if(is(typeof(R._input.takeExactly(2)) == R)){
alias R Hello;
}


That's the nicest.


Well, I noticed it is not entirely correct as takeExactly special cases
sliceable inputs. Therefore, the guard also passes for ranges that have
a sliceable member called _input of the same range type. The correct
guard therefore would be:

if(hasSlicing!R || is(typeof(R._input.takeExactly(2)) == R))

or

if(!hasSlicing!R && is(typeof(R._input.takeExactly(2)) == R))

depending on what the goal is.



Regarding availability of "_input", I meant to make
it available systematically as "input" for ranges where the notion makes
sense.

Andrei


This seems to be reasonable.


Re: Testing for template argument being result of takeExactly

2012-09-23 Thread Timon Gehr

On 09/23/2012 10:57 PM, Ali Çehreli wrote:

...

Also, I think your code should have passed a range like R.init to
takeExactly, not R, which is a type:

   takeExactly(R.init, 1)

I don't know why your code compiles.



See discussion here:
http://d.puremagic.com/issues/show_bug.cgi?id=8220



Re: Testing for template argument being result of takeExactly

2012-09-24 Thread Timon Gehr

On 09/24/2012 09:41 AM, monarch_dodra wrote:

...

Regarding the ".init" issue, I hadn't thought of that, but it can
be worked around pretty easily with an is(R r):


template Hello(R)
  if ( is(R r) &&
   is(typeof(takeExactly(r, 1))) &&
   is(R == typeof(takeExactly(r, 1)))
  )
{
  alias R Hello;
}

After that, I guess it is indeed one implementation detail vs the
other.



I don't think this does what you think it does. The 'is(R r)' declares r 
to be an alias for R. So 'r' is a type in that code snippet.


Also, is(typeof(takeExactly(R, 1))) && is(R == typeof(takeExactly(R, 1)))

can be written in a more compact way as

is(typeof(takeExactly(R, 1)) == R)



IMO, it really depends on whether or not you'd want "int[]" to be
considered the return type of a takeExactly :/ Maybe it is, maybe
it ain't.




Re: Testing for template argument being result of takeExactly

2012-09-26 Thread Timon Gehr

On 09/25/2012 08:41 AM, monarch_dodra wrote:

On Monday, 24 September 2012 at 22:13:51 UTC, Timon Gehr wrote:

On 09/24/2012 09:41 AM, monarch_dodra wrote:
> [SNIP]

I don't think this does what you think it does. The 'is(R r)' declares
r to be an alias for R. So 'r' is a type in that code snippet.


Darn :(


Also, is(typeof(takeExactly(R, 1))) && is(R == typeof(takeExactly(R, 1)))

can be written in a more compact way as

is(typeof(takeExactly(R, 1)) == R)


Technically, no: That was my first try, and as mentioned in the first
reply, this returns true when the types of takeExactly and R are equal
comparable, but does not make sure they are the actually the same types.
...


I assume you messed up the parentheses.

is(typeof(takeExactly(R, 1) == R)) // test for equal-comparable
is(typeof(takeExactly(R, 1)) == R) // test for type identity

alias float flt;
static assert(is(typeof(1==flt)));
static assert(!is(typeof(1)==flt));


Re: Testing for template argument being result of takeExactly

2012-09-26 Thread Timon Gehr

On 09/26/2012 03:50 PM, monarch_dodra wrote:

On Wednesday, 26 September 2012 at 13:19:13 UTC, Timon Gehr wrote:

On 09/25/2012 08:41 AM, monarch_dodra wrote:

On Monday, 24 September 2012 at 22:13:51 UTC, Timon Gehr wrote:

On 09/24/2012 09:41 AM, monarch_dodra wrote:
> [SNIP]

I don't think this does what you think it does. The 'is(R r)' declares
r to be an alias for R. So 'r' is a type in that code snippet.


Darn :(


Also, is(typeof(takeExactly(R, 1))) && is(R == typeof(takeExactly(R,
1)))

can be written in a more compact way as

is(typeof(takeExactly(R, 1)) == R)


Technically, no: That was my first try, and as mentioned in the first
reply, this returns true when the types of takeExactly and R are equal
comparable, but does not make sure they are the actually the same types.
...


I assume you messed up the parentheses.

is(typeof(takeExactly(R, 1) == R)) // test for equal-comparable
is(typeof(takeExactly(R, 1)) == R) // test for type identity

alias float flt;
static assert(is(typeof(1==flt)));
static assert(!is(typeof(1)==flt));


Yes sorry. I miss read that.

Kind of weird though, could you explain why:

struct S{};

is(typeof(takeExactly(S, 1)) == S) //false
is(S == typeof(takeExactly(S, 1))) //Error: template
std.range.takeExactly does not match any function template declaration

I was under the understanding that == was a commutative operation. Not
the case in an is block?


It is special syntax, not an == operator. is-expressions suppress errors
in the first argument only.


Re: Testing for template argument being result of takeExactly

2012-09-26 Thread Timon Gehr

On 09/26/2012 05:08 PM, Andrei Alexandrescu wrote:

On 9/26/12 9:50 AM, monarch_dodra wrote:

struct S{};

is(typeof(takeExactly(S, 1)) == S) //false
is(S == typeof(takeExactly(S, 1))) //Error: template
std.range.takeExactly does not match any function template declaration


Neither should work. The expression should be takeExactly(S.init, 1).

Andrei


http://d.puremagic.com/issues/show_bug.cgi?id=8220
https://github.com/D-Programming-Language/dmd/pull/1007



Re: template condition

2012-09-27 Thread Timon Gehr

On 09/27/2012 03:01 PM, Namespace wrote:

Is there any difference between these two code snippets:

#1:
struct Foo(T : Object) {

#2:
struct Foo(T) if (is(T == class)) {

?

I ask because I prefer option #1, but I see most often in Phobos variant
#2.


Yes there is:

struct S{
Object o;
alias o this;
}

#1 accepts S, #2 does not.


Re: Struct assignment, possible DMD bug?

2012-09-29 Thread Timon Gehr

On 09/29/2012 06:26 PM, Maxim Fomin wrote:

On Saturday, 29 September 2012 at 16:05:03 UTC, ixid wrote:

This behaviour seems inconsistent and unintuitive:

void main() {
int[3] a = [1,2,3];
a = [4, a[0], 6];

struct S {
int a, b, c;
}

S s = S(1,2,3);
s = S(4, s.a, 6);

assert(a == [4,1,6]);
assert(s == S(4,4,6));
}

Setting the struct writes s.a before evaluating it while the reverse
is true of the array assignment. Using DMD 2.0.60. GDC does what I'd
expect and gives both as 4,1,6.


I think this is notorious "i = ++i + ++i".


There is only one mutating sub-expression.


Statement s = S(4, s.a, 6) writes to s object and simultaneously reads it.
http://dlang.org/expression.html states that assign expression is
evaluated in implementation defined-manner and it is an error to depend
on things like this.


No evaluation order of the assignment expression can possibly lead to
this result. This seems to be a DMD bug.


Re: Struct assignment, possible DMD bug?

2012-09-29 Thread Timon Gehr

On 09/30/2012 12:51 AM, Ali Çehreli wrote:

On 09/29/2012 11:16 AM, Timon Gehr wrote:
 > On 09/29/2012 06:26 PM, Maxim Fomin wrote:

 >>> S s = S(1,2,3);
 >>> s = S(4, s.a, 6);
 >>>
 >>> assert(a == [4,1,6]);
 >>> assert(s == S(4,4,6));
 >>> }
 >>>
 >>> Setting the struct writes s.a before evaluating it while the reverse
 >>> is true of the array assignment. Using DMD 2.0.60. GDC does what I'd
 >>> expect and gives both as 4,1,6.
 >>
 >> I think this is notorious "i = ++i + ++i".
 >
 > There is only one mutating sub-expression.

But that mutation is happening to an object that is also being read
inside the same expression.

This is one of the definitions of undefined behavior, not a compiler bug.

 >> Statement s = S(4, s.a, 6) writes to s object and simultaneously reads
 >> it.
 >> http://dlang.org/expression.html states that assign expression is
 >> evaluated in implementation defined-manner and it is an error to depend
 >> on things like this.
 >
 > No evaluation order of the assignment expression can possibly lead to
 > this result. This seems to be a DMD bug.

The compiler seems to be applying an optimization, which it is entitled
to as long as the language definition is not violated.



Technically there is no language definition to violate.


If we are using the same object both to read and write in the same
expression, then we should expect the consequences.



No. Why?


Disclaimer: I assume that D's rules are the same as C and C++ here.



C and C++ do not have struct literals and if I am not mistaken,
constructor invocation is a sequence point.

Besides, this does not make any sense, what is the relevant part of the 
standard?


int c = 0;
c = c+1; // c is both read and written to in the same expression


Re: liittle question about reduce

2012-09-29 Thread Timon Gehr

On 09/30/2012 01:04 AM, bioinfornatics wrote:

hi,


int[] list = [ 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];

why this do not works ?
list.reduce!( (a,b) => a + b )( 0 ); // sum all elements

but by this way that is ok:
reduce!( (a,b) => a + b )( 0, list ); // sum all elements





Because of the parameter order.

0.reduce!((a,b)=>a+b)(list); // works


Re: Functional vs simple code

2012-10-02 Thread Timon Gehr

On 10/02/2012 10:48 PM, ixid wrote:

Without optimization the range and algorithm method takes about 10 times
as long as the simple code below it, with no array bounds checking and
optimization it takes six times as long. Why is the difference so huge?
I'd expect a moderate overhead but that's a big difference.

module main;
import std.stdio, std.algorithm, std.range, std.datetime;

enum MAX = 10_000_000UL;

void main() {
 StopWatch sw;
 sw.start;

 auto sum1 = MAX.iota.map!(x => x * x).reduce!"a + b";

 sw.peek.msecs.writeln("msecs");
 sum1.writeln;
 sw.start;

 ulong sum2 = 0;
 foreach(i;0..MAX)
 sum2 += i * i;

 sw.peek.msecs.writeln("msecs");

 sum2.writeln;
}



$ cat ixidbench.d
module main;
import std.stdio, std.algorithm, std.range, std.datetime;

enum MAX = 10_000_000_000UL;

void main() {
StopWatch sw;
sw.start;

auto sum1 = MAX.iota.map!(x => x * x).reduce!"a + b";

sw.stop;
sw.peek.msecs.writeln("msecs");
sum1.writeln;
sw.reset;
sw.start;

ulong sum2 = 0;
foreach(i;0..MAX)
sum2 += i * i;

sw.stop;
sw.peek.msecs.writeln("msecs");

sum2.writeln;
}
$ ldmd2 -O -release -inline ixidbench.d -ofixidbench
$ ./ixidbench
6528msecs
7032546979563742720
7518msecs
7032546979563742720


Re: Functional vs simple code

2012-10-02 Thread Timon Gehr

On 10/03/2012 12:11 AM, Timon Gehr wrote:

...

$ cat ixidbench.d
module main;
import std.stdio, std.algorithm, std.range, std.datetime;

enum MAX = 10_000_000_000UL;

void main() {
 StopWatch sw;
 sw.start;

 auto sum1 = MAX.iota.map!(x => x * x).reduce!"a + b";

 sw.stop;
 sw.peek.msecs.writeln("msecs");
 sum1.writeln;
 sw.reset;
 sw.start;

 ulong sum2 = 0;
 foreach(i;0..MAX)
 sum2 += i * i;

 sw.stop;
 sw.peek.msecs.writeln("msecs");

 sum2.writeln;
}
$ ldmd2 -O -release -inline ixidbench.d -ofixidbench
$ ./ixidbench
6528msecs
7032546979563742720
7518msecs
7032546979563742720


$ gdmd -O -release -inline ixidbench.d -ofixidbench
$ ./ixidbench
11250msecs
7032546979563742720
11233msecs
7032546979563742720





Re: Question about anonymous delegates.

2012-10-03 Thread Timon Gehr

On 10/03/2012 03:53 PM, Sharp wrote:

I found something what I don't understand.

Here is a simplifed code with comments:
http://dpaste.dzfl.pl/a914d11a

I creating anonymous delegates, whose function is to modify their
parameter. Their parameters are different class references.
I pass these class references to anonymous delegates, but the delegates
obtain only the last passed class reference.

Thanks for your answers.


class Num {
int a;
}

void main(){
auto nums = new Num[10];
alias void delegate() Func;
auto funcs = new Func[10];
// workaround for 
http://d.puremagic.com/issues/show_bug.cgi?id=2043 ahead:

for(int i = 0; i < 10; ++i) (){
Num num = nums[i] = new Num();
int i=i; // fix for bug in your code
funcs[i] = {num.a = i;};
}();
foreach(num; nums) {
assert(num.a == 0);
}
foreach(func; funcs) {
func();
}
foreach(i, num; nums) {
assert(num.a == i);
}
}


Re: Function pointer variable not recognized as function by is-operator

2012-10-07 Thread Timon Gehr

On 10/07/2012 10:35 AM, Jonathan M Davis wrote:

On Sunday, October 07, 2012 10:25:41 Tommi wrote:

The following compiles, which I'm pretty sure must be a bug,
right? Just checking to be sure I won't be polluting the bug
tracker.

void main()
{
  auto f = (int i) {};
  static assert (!is(f == function)); // should fail
  static assert (!is(f == delegate));
}


It's not a bug. is(f == function) checks for functions, not function pointers.

http://stackoverflow.com/questions/11067972

- Jonathan M Davis



Actually is(f==function) checks whether or not f is a function type.
The ==function part is unimportant, because f is not even a type.


Re: Using inout in delegates

2012-10-08 Thread Timon Gehr

On 10/05/2012 04:09 PM, Ali Çehreli wrote:

...

This workaround makes the compiler happy:

void foo (inout(int)[] arr)
{
 auto a = (inout int) { auto b = arr[0]; };
}

But probably not what you want. :/

IIRC, inout has bugs and incomplete implementation. I think this should
be in the bug database.

Ali


The original behaviour is to be expected and the workaround exploits a 
compiler bug.


The correct way to get rid of the compile error is:

void foo(inout(int)[] arr){
auto a = { const b = arr[0]; } // or int b = arr[0];
}


Re: Calling un-overridden class method

2012-10-12 Thread Timon Gehr

On 10/13/2012 04:22 AM, H. S. Teoh wrote:

...
// PROBLEM #1: due to PROBLEM #1, this causes an
// infinite recursion that eventually overflows
// the stack.
...


I'm sure it does :).
@topic: yes this is a bug.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Timon Gehr

On 10/13/2012 06:02 PM, Maxim Fomin wrote:

...
Different groups of people have different mind and same things produce
different sense on them. From my point of view operator overloading
methods are special functions and not treating them as candidates for
UFCS does make more sense.


I do not understand how an operation that happens to be called '+' is 
fundamentally different from an operation that is called 'add'.



Even if you convince in your opinion,
language addition without applied purposes makes no benefit.


I guess the functionality could be achieved in DMD mostly by removing
code. (Code for good error messages excluded!)


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Timon Gehr

On 10/13/2012 10:15 PM, Jonathan M Davis wrote:

...
construct is using syntactic sugar such as UFCS, because _all_ of that
syntactic sugar must be lowered to code which _isn't_ syntactic sugar anymore.


That is not what lowering means.


It would be far more expensive to have to continually make passes to lower
code over and over again until no more lowering was required than it would be
to just have to lower it once.
...


It does not have to be implemented it in an inefficient way. It is
actually simpler for a sane compiler implementation to make UFCS apply
to lowered overloaded operators than to restrict it.


You're reading way to much into what TDPL is saying. It's simply telling you
about how the compiler goes about translating code which uses operators such
as +, >, or = into the functions that you used to overload them. It's _not_
telling you that it'll do UFCS on overloaded operator functions.


It is telling us that

a+b
is transformed to
a.opBinary!"+"(b)

UFCS applies to a.opBinary!"+"(b).


Heck,
technically, TDPL never really says that D _has_ UFCS. It talks about the
member call function syntax for _arrays_ (which D had for ages before it had
UFCS), not for types in general. It's only very recently that full UFCS has
been added to the language.


Exactly, so what is the point? If TDPL does not talk about the UFCS
feature, then TDPL not talking about UFCS in the context of one
specific case certainly cannot be used as an argument to justify that
it should not apply in that case.


Both overloaded operators and UFCS use lowering to generate different code
which the compiler then compiles,


By using the same strategy recursively, otherwise it is not called lowering.


but they _aren't_ mixed and they will
_never_ be mixed. If it had _ever_ been intended that it be possible to
overload operators as free functions, then we'd simply have made it so that
you could declare a free function like

auto opBinary(string op)(Foo foo, Bar bar)
{
...
}

in the first place  without requiring that it be a member function.


You can.


But it _was_
required to be a member function, and it would make no sense to allow a new
feature to circumvent that restriction. If it was supposed to be
circumventable, then the restriction wouldn't have been put there in the first
place.


This argument is even less convincing in the context of an informally
specified language with a somewhat buggy reference compiler.


Re: Operator overloading through UFCS doesn't work

2012-10-13 Thread Timon Gehr

On 10/14/2012 12:36 AM, H. S. Teoh wrote:

On Sun, Oct 14, 2012 at 12:12:01AM +0200, Timon Gehr wrote:

On 10/13/2012 10:15 PM, Jonathan M Davis wrote:

[...]

but they _aren't_ mixed and they will _never_ be mixed. If it had
_ever_ been intended that it be possible to overload operators as
free functions, then we'd simply have made it so that you could
declare a free function like

auto opBinary(string op)(Foo foo, Bar bar)
{
...
}

in the first place  without requiring that it be a member function.


You can.


But it _was_ required to be a member function, and it would make no
sense to allow a new feature to circumvent that restriction. If it
was supposed to be circumventable, then the restriction wouldn't have
been put there in the first place.


This argument is even less convincing in the context of an informally
specified language with a somewhat buggy reference compiler.


OK, before this thread devolves into a shouting match, I'd like to
understand what was the rationale behind this restriction. What were the
reasons behind not allowing a non-member function to overload an
operator? What are the pros and cons considered at the time, and how do
they weigh now? Or was it just a matter of not being implemented because
nobody thought about it at the time?


T



Afaik free-function operator overloads (but not in the context of
UFCS) were considered and turned down because D did not want to get
amidst discussions about adding Koenig lookup. UFCS does not do Koenig
lookup.


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

On 10/15/2012 01:00 PM, Artur Skawina wrote:

...

An overloaded operator is just another normal method; you get the same type of
problems when dealing with "normal" methods - eg in types having an "alias 
this" -
  an UFCS "method" must take precedence over one reachable via the alias - just 
like
in the overloaded op case. The only sane alternative would be disallowing UFCS
for types with an "alias this" (which would be a severe limitation).
...


Just no. Why make symbol lookup even more complicated just in order to
add an strange exception to the language that either enables new forms
of hijacking or would be a severe limitation?


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

On 10/16/2012 05:57 PM, Maxim Fomin wrote:

...

At NG discussion it may look nice to define some type and then add
operator overloading methods


Operator overloading is not magic, so your statement can be shortened to

... and then add methods

Which is still not correct, because that is not what UFCS does.



but as soon as you import some other
modules, authors of which also consider UFCS operators a good idea,


Who has stated that? It just does not make sense to explicitly ban
them, as they are not special.


everything breaks including namespace conflict


The usual disambiguation procedures apply. (Which are broken in DMD at
the moment, because module-scope private symbols can cause conflicts.)

Infix operators are not special. It is just notation.


as well as loosing
ability to manipulate that type within built-in expression as well.


I did not get that.


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

On 10/14/2012 09:14 AM, Maxim Fomin wrote:

On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:

Actually, it seems that alias this has precedence over UFCS. So, a
free function opUnary wouldn't ever suit better than an actual method
opUnary of the thing referred to by that alias this.


http://dpaste.dzfl.pl/d0a4431d

Free function doesn't suit better than actual method. The issue is
absence of the actual method.

opUnary method has priority over alias this, which does make sense
because alias this is chosen only when it is impossible to apply
operation over A type. If this request is approved and compiler has
opUnary definition outside type (which suits better then alias this)
such function would hijack alias this. If not, there is a new case when
something is going special than at usual cases and only for the purpose
of writing operator overloading methods outside the body of the type.


The goal must be to get rid of all special behaviour that can result in
strange interactions.
Add the suitable operator function templates to built-in types. Always
rewrite operators to operator function calls. Problem solved.
(And people are already asking for custom constant folding procedures,
even without having this in place to use as a supporting argument.)


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

On 10/14/2012 09:01 AM, Maxim Fomin wrote:

On Saturday, 13 October 2012 at 19:50:02 UTC, Timon Gehr wrote:

On 10/13/2012 06:02 PM, Maxim Fomin wrote:

...
Different groups of people have different mind and same things produce
different sense on them. From my point of view operator overloading
methods are special functions and not treating them as candidates for
UFCS does make more sense.


I do not understand how an operation that happens to be called '+' is
fundamentally different from an operation that is called 'add'.


The first one is an operator, which sometimes, may be rewritten to
function call, the second one is a function call.



What is the difference between an operator and a function call? Is it
important?

int add(int a, int b){ return a+b; }
// or conversely (not valid syntax):
int (int a)+(int b){ return add(a,b); }



Even if you convince in your opinion,
language addition without applied purposes makes no benefit.


I guess the functionality could be achieved in DMD mostly by removing
code. (Code for good error messages excluded!)


I don't understand what you are trying to say. Anyway, you can write a
pull request and propose it at github. It would be interesting to see
reaction of others.


Built-in types shouldn't be special except maybe that the parser
recognises related keywords.

It should go like this:

a + b => a.opBinary!"+"(b); // opBinary_r woes left out,
// but would require treatment
a + b => __add(a,b); // if a and b of built-in type
a.opBinary!"+"(b) => __add(a,b); // if a and b of built-in type

Where __add(a,b) is the representation of an AST node of a built-in add
operation involving operands a and b.

All the code in DMD that supposedly tries to make up for this kind of
inconsistencies (and sometimes fails, because it does not catch all the
ways the language features interact) can be gotten rid of.



Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

On 10/17/2012 01:51 PM, Maxim Fomin wrote:

On Wednesday, 17 October 2012 at 11:11:26 UTC, Timon Gehr wrote:

On 10/14/2012 09:14 AM, Maxim Fomin wrote:

On Sunday, 14 October 2012 at 07:01:30 UTC, Tommi wrote:

Actually, it seems that alias this has precedence over UFCS. So, a
free function opUnary wouldn't ever suit better than an actual method
opUnary of the thing referred to by that alias this.


http://dpaste.dzfl.pl/d0a4431d

Free function doesn't suit better than actual method. The issue is
absence of the actual method.

opUnary method has priority over alias this, which does make sense
because alias this is chosen only when it is impossible to apply
operation over A type. If this request is approved and compiler has
opUnary definition outside type (which suits better then alias this)
such function would hijack alias this. If not, there is a new case when
something is going special than at usual cases and only for the purpose
of writing operator overloading methods outside the body of the type.


The goal must be to get rid of all special behaviour that can result in
strange interactions.
Add the suitable operator function templates to built-in types. Always
rewrite operators to operator function calls. Problem solved.
...


You have a struct with alias this to int without overloaded operators.
It (say, struct.d) contains code with structure increments. Some other
module (say bob.d), which import the structure, defines function
supposed to overload opUnary. If operators are always rewritten to
function calls, now function should be called in module bob.d, as well
as in struct.d if they are compiled together. It certainly not what
author of struct.d expected. The case can be even more interesting, if
alias this in struct.d were absent at a time when bob.d was written and
at some point of future Bob is updating his sources.



Members do not cause conflicts with free functions.
Alias this takes precedence as it is a member of the type.
What is the issue?


Re: Operator overloading through UFCS doesn't work

2012-10-17 Thread Timon Gehr

On 10/17/2012 01:32 PM, Maxim Fomin wrote:

On Wednesday, 17 October 2012 at 11:00:05 UTC, Timon Gehr wrote:

On 10/16/2012 05:57 PM, Maxim Fomin wrote:

...

At NG discussion it may look nice to define some type and then add
operator overloading methods


Operator overloading is not magic, so your statement can be shortened to

... and then add methods

Which is still not correct, because that is not what UFCS does.



It is not correct as long as you cavil at lexis, however the statement
has room for correction.



In a discussion it is crucial that both parties agree on a common set
of terms and definitions. Otherwise agreement cannot be detected.


but as soon as you import some other
modules, authors of which also consider UFCS operators a good idea,


Who has stated that? It just does not make sense to explicitly ban
them, as they are not special.


Who stated that they should be "explicitly banned"?


Well, you did, if I got that right:

On 10/13/2012 06:02 PM, Maxim Fomin wrote:

From my point of view operator overloading methods are special functions
and not treating them as candidates for UFCS does make more sense.


(Explicitly banning UFCS operators is the same thing as not treating
rewritten operators as candidates for UFCS.)


I explained potential problem in previous posts.



Yes, several times, but to me the argument still looks similar to the
following (note that only the 'counter argument' part is related to
this discussion):

Issue: the 'body' keyword is not used enough to warrant keyword status,
parsing could succeed without making it a full keyword.

Proposed solution: make 'body' a valid identifier that is only
recognised as special where it is expected to occur.

Main counter argument: Two people might define a symbol using the newly 
available 'body' identifier, which can cause symbol conflicts.


Do you agree with this reasoning, and if not, what is the fundamental
difference between this and the point you are trying to convey?



everything breaks including namespace conflict


The usual disambiguation procedures apply. (Which are broken in DMD at
the moment, because module-scope private symbols can cause conflicts.)

Infix operators are not special. It is just notation.


as well as loosing
ability to manipulate that type within built-in expression as well.


I did not get that.


Again, the problem is in conflict between different declared operator
overloading functions across different modules.


Can you explain the usage of the term 'built-in' in this context?


Re: Returning dynamic array from the function

2012-10-17 Thread Timon Gehr

On 10/17/2012 10:15 PM, sclytrack wrote:

On Wednesday, 17 October 2012 at 19:46:51 UTC, bearophile wrote:

sclytrack:


It doesn't give an error when marking the function with safe.

@safe
int[] create()
{
}


I think marking it @safe is not relevant. In theory a good type system
should give an error message on similar code. I don't know if D is
supposed to spot similar error situations.

Bye,
bearophile


If that's the case then they should call it safeR D instead of safe D.


I think what he meant to say was that it should be illegal to do this
even in @system code, not that it is OK that it passes with @safe.


Re: opCast using in template struct

2012-10-18 Thread Timon Gehr

On 10/18/2012 11:45 PM, bearophile wrote:

Era Scarecrow:


It's an easy mistake to make. Maybe the compiler should issue a
warning when opAssign attempts and fails and opOpBinary is defined.




This would have to be implemented very carefully. There are enough
hard to reproduce symbol resolution bugs already. It does not get
better by introducing hidden and unnecessary lookups.


If you have strong feelings about this, then add a Bugzilla entry.

There are other cases. Generally the D compiler should add some warnings
that help against operator overloading mistakes.

Bye,
bearophile


I don't think that operator overloading gives rise to distinct mistakes.
For example, better error messages that just specify the expected name,
as in other cases of undefined identifiers, would already fix this.


Re: opCast using in template struct

2012-10-18 Thread Timon Gehr

On 10/19/2012 01:05 AM, Era Scarecrow wrote:

On Thursday, 18 October 2012 at 22:07:55 UTC, Timon Gehr wrote:

On 10/18/2012 11:45 PM, bearophile wrote:

There are other cases. Generally the D compiler should add some
warnings that help against operator overloading mistakes.


I don't think that operator overloading gives rise to distinct
mistakes. For example, better error messages that just specify the
expected name, as in other cases of undefined identifiers, would
already fix this.


  Inside a function a badly named identifier becomes obvious since it
outright tells you. But with regards to opOpAssign and other operator
overloading I see the error message and I see the call but I don't see
why it fails.


My suggestion was something like:

error: expression 'e' of type 'S' is not of arithmetic type and it does 
not define opOpAssign!"+".


The compiler should indicate exactly why it fails. If this is not
enough, then the programmer certainly deserves the headache.


Then I'll try adjusting the signature on my function, not
realizing it never sees it in the first place due to misspelling.



If the issue _is_ with the signature, then the compiler should tell you.
That is the (secondary) job of the compiler.


  Maybe.. A general warning when something starts with 'op(Op)?[A-Z]'


'op[A-Z]'


but doesn't actually qualify as any of the override-able operators? That
seems sensible...


That is a lot better, but what if the typo is within the first 3
characters? :o)


Re: opCast using in template struct

2012-10-18 Thread Timon Gehr

On 10/19/2012 01:23 AM, bearophile wrote:

Era Scarecrow:


 Maybe.. A general warning when something starts with 'op(Op)?[A-Z]'
but doesn't actually qualify as any of the override-able operators?
That seems sensible...


Regarding operator overloading there are several situations worth
warning the programmer of. The D compilers should be improved on this.

Bye,
bearophile


What situations?


<    2   3   4   5   6   7   8   9   10   >