Re: opAssign and references

2012-01-31 Thread Timon Gehr

On 01/31/2012 06:15 PM, Nicolas Silva wrote:

Hi,


Works for me. Which version of the compiler are you using?


Sorry, i forgot to mention: i'm using dmd 2.057 on ubuntu 32bit.



I am using DMD 2.057 on Ubuntu 64bit. Are you sure that it does not 
work? Can anyone reproduce the error?


import std.variant;
struct Foo {
Variant a;
ref Variant refA(){
return a;
}
}
void main(){
Foo f1;
f1.refA() = 24;
}



Re: floating-WTF - Compiler-BUG with 64bit

2012-01-28 Thread Timon Gehr

On 01/28/2012 04:56 PM, sclytrack wrote:

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

On 01/24/2012 10:28 PM, %u wrote:

Shouldn't this go into 'digitalmars.D' ?


It should go straight to the bug tracker.


Issue 7391 - floating wtf dmd 2.057 64


Thanks!


Re: Using Clang with D

2012-01-26 Thread Timon Gehr

On 01/26/2012 08:44 PM, Jacob Carlborg wrote:

On 2012-01-26 10:29, Jacob Carlborg wrote:

I'm trying to port a simple example that uses Clang from C to D but for
some reason the D version results in a segmentation fault.

This is the C code:
http://pastebin.com/4B2JGz9n

This is the D code:
http://pastebin.com/XPBsSVup

The stacktrace from GDB looks like this:

(gdb) r
Starting program: /Users/jacob/development/d/dstep/bin/dstep NSObject.h
Reading symbols for shared libraries .+.. done

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0004
0x000100104139 in clang_formatDiagnostic ()
(gdb) bt
#0 0x000100104139 in clang_formatDiagnostic ()
#1 0x00011648 in _Dmain ()
#2 0x00010001baa5 in D2rt6dmain24mainUiPPaZi7runMainMFZv ()
#3 0x00010001b671 in D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#4 0x00010001baf7 in D2rt6dmain24mainUiPPaZi6runAllMFZv ()
#5 0x00010001b671 in D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv ()
#6 0x00010001b5f4 in main ()

I'm using DMD 2.057 on Mac OS X compiling as 64bit.

Any idea what I have done wrong?


I've now found out that I only get this error when compiling as 64bit.
When I compile as 32bit everything works fine.



It is possibly an error in the bindings. What are the C and D 
declarations of the methods you are using?


Re: Invalid bounding interval [, ]

2012-01-25 Thread Timon Gehr

On 01/25/2012 12:28 PM, C wrote:

auto chunk = new ubyte[1024];
foreach(ref x; chunk) x = uniform![](ubyte.min, ubyte.max);


Thank you all for your replies.

@ Timon, I have two questions:
1) How come you can omit parentheses for uniform's parameter, shouldn't it be
  uniform!([])(...) ?


If there is only one template argument, parentheses can be omitted.


2) Does auto chunk = new ubyte[1024]; ALWAYS create a dynamic array with
changeable length?
That is a silly question but the syntax confuses me.


Yes it does. But this works too and is probably more intuitive if you 
are not familiar with other C-derived languages:


auto chunk = new ubyte[](1024);


Re: Invalid bounding interval [, ]

2012-01-25 Thread Timon Gehr

On 01/25/2012 04:50 AM, bearophile wrote:

C:


I want to fill a ubyte array with random data.


In D ubytes are not char, they are two different types. So if you want ubytes, 
then use ubytes:
uniform!([])(ubyte.min, ubyte.max)


Regarding your error, a reduced test case:

import std.random: uniform;
void main() {
 uniform!([])(char.min, char.max);
 uniform!((])(char.min, char.max);
}

Bye,
bearophile


Even more reduced test case and bug report:
http://d.puremagic.com/issues/show_bug.cgi?id=7367


Re: Invalid bounding interval [, ]

2012-01-25 Thread Timon Gehr

On 01/25/2012 04:25 AM, C wrote:

I want to fill a ubyte array with random data.
The code compiles with no warnings or errors.

Source snippet:

 auto prng = Random(unpredictableSeed);
 ubyte[] chunk;

 chunk.length = 1024;

 fill(chunk, uniform!([])('\x00', '\xFF', prng));

Error (at runtime):

object.Exception@c:\dmd2\windows\bin\..\..\src\phobos\std\random.d(971):
std.random.uniform(): invalid bounding interval [ , �]

423C50
423AC7
404EA8
404EEC
404AE3
4A6109


Also I lost the URL for this forum, all I see is this nasty PHP News Reader
interface.
Thank you.


The code wouldn't do what you intended even if it compiled. Use this:

auto chunk = new ubyte[1024];
foreach(ref x; chunk) x = uniform![](ubyte.min, ubyte.max);


Re: Meaning of const

2012-01-25 Thread Timon Gehr

On 01/25/2012 02:29 AM, H. S. Teoh wrote:

On Tue, Jan 24, 2012 at 08:01:41PM -0500, bearophile wrote:

Jonathan M Davis:


Now, the confusing part is the fact that unlike C++, D allows you to put the
const for making the function on the _left-hand_ side of the function (C++
only lets you put it on the right). This is to increase consistency between
modifers (public, override, pure, etc.) - they _all_ can go on both the right
and left (which is very unfortunate in the case of const and immutable IMHO).
That means that const (and immutable) always modify the function rather than
the return value unless you use parens.


Some time ago we have discussed this topic in an enhancement request in 
Bugzilla. The idea was to disallow code like:


struct Foo {
 int x;
 const const(int) bar() {
 return 0;
 }
}
void main() {}


and require the struct const, immutable to be only on the right if present.
Walter shot this idea down for consistency. But I generally don't want
consistency when it's just a potential source of confusion for the
programmer :-)

[...]

How can this be consistency? For example:

class A {
const int x;
@property const int y();
}

Now you have typeof(A.x)==const(int) and typeof(A.y)==int. Seems quite
inconsistent to me.

But since Walter doesn't like the idea of restricting the syntax to 'int
y() const', then what about making it mandatory to write:

const(int) x;

instead of:

const int x;

?


You essentially propose to remove the const/immutable/shared/inout 
storage classes for variables. It would break almost every D program and 
I don't see many benefits.


Requiring the parentheses is a bit extreme, I admit, but it touches upon
another area of D syntax that I don't quite like, and that is const or
immutable applied to arrays:

const(int)[] x; // array of const(int)
const(int[]) x; // const array of int
const int[] x;  // ??? const array of const int? Or one
// of the above?


const(int[]).


The storage class of a declaration applies to the whole declaration.


It gets worse when you throw in ref:


Ref does not change anything but the calling convention *of the 
function*. The reference itself cannot be rebound, there is no syntax 
for it.




ref int f();// returns int* (I think?)
ref const(int) f(); // returns const(int)* (?)
ref const int f();  // ???
const ref int f():  // ???

The last line is quite bad. Is the return type const(int*) or
const(int)*, or is it just int* (i.e., const applies to f not the return
value)?


It is int.



ref const(int)[] x; // ref to array of const(int)?


Note that ref can only be on a function or on a parameter.


const(ref int)[] x; // array of refs to int?


No such thing exists.


const ref int[] x;  // array of ???


const(int[]). Declaration is invalid, would have to be a parameter.


const ref int[] x();// const function that returns ref int[]?


It returns int[], by reference. It is equivalent to

int[] x()const ref;

Though most people will prefer to have 'ref' on the lhs:

ref int[] x()const;

It still applies to the function though.


const const ref int[] x();  // const function returning what?


Redundant storage class const.

ref int[] x()const const; is the same thing.



The more I think about this, the more confusing it becomes.


It is very simple. What may be confusing you is that 
const/immutable/shared/inout are both type constructors and storage classes.



If
parentheses were mandatory after const, things would be much, much
better:

const(ref int) x;
const(ref const(int)) x;
... etc.

Much clearer to me.


It is not to me. This is not valid syntax. Also, types of the general 
form const(...const(...)...) don't make a lot of sense. Const is transitive.




Re: Meaning of const

2012-01-25 Thread Timon Gehr

On 01/26/2012 12:35 AM, H. S. Teoh wrote:

On Wed, Jan 25, 2012 at 11:50:57PM +0100, Timon Gehr wrote:

On 01/25/2012 02:29 AM, H. S. Teoh wrote:

[...]

But since Walter doesn't like the idea of restricting the syntax to 'int
y() const', then what about making it mandatory to write:

const(int) x;

instead of:

const int x;

?


You essentially propose to remove the const/immutable/shared/inout
storage classes for variables. It would break almost every D program
and I don't see many benefits.

[...]

It is very simple. What may be confusing you is that
const/immutable/shared/inout are both type constructors and storage
classes.

[...]

Ah, I see. This is very helpful.

So what's the difference between a const int type, and an int variable
with const storage class?

I think this is the key issue. The syntax makes this distinction
non-obvious, IMHO, which is very confusing.


The syntax is clear on it: If it is followed by parentheses, it is a 
type constructor. Otherwise it is a storage class.



This ambiguity also shows up
in function definitions (allowing storage classes to appear left or
right of the function name/parameters), which we discussed earlier. From
what I can tell, Walter doesn't want to change this, but I have to say
that this is one part of D I find unnecessarily confusing.



For variables, the storage class just implies that the type will be 
wrapped in the respective type constructor. The storage class still 
'talks' about the whole declaration though.

A key application is for type deduction:

immutable a = foo();

Foo may return something mutable, and a will automatically have it's 
type deduced to the respective immutable type.


Storage classes always apply to the whole declaration they refer to. It 
is _not_


const intx;

and

const int  foo;

but:

constint x;

and

const  int foo(){}








Re: actors library?

2012-01-24 Thread Timon Gehr

On 01/24/2012 07:51 PM, xancorreu wrote:

Al 24/01/12 13:37, En/na Dejan Lekic ha escrit:

Xan, read this article please:
http://www.informit.com/articles/article.aspx?p=1609144

You have exactly what you are looking for in the D runtime and
standard library.

I read it and **after** I post the question. I don't know how
std.concurrency is related to actors model. Can you enlight me?

Thanks,
Xan.


std.concurrency is an implementation of the actor model.
'Actor model' does not imply 'Object Oriented'.

Example 1:

import std.stdio, std.concurrency;
void myActor() {
try {
for(;;){
receive(
(int i){ writeln(Received integer: ,i); }
);
}
}catch(Exception e){
// cleanup
}
}

void main() {
auto actor = spawn(myActor);
foreach(i;0..10) actor.send(i);
}

Example 2:

import std.stdio, std.concurrency;
import core.thread;
alias Thread.sleep sleep;
void ping() {
Tid pong;
try {
for(;;){
receive(
(string s){
writeln(ping received ,s);
sleep(dur!seconds(1));
pong.send(ping);
},
(Tid newPong){ pong = newPong; }
);
}
}catch(Exception e){}
}

void pong(Tid ping) {
try {
ping.send(pong);
for(;;){
receive(
(string s){
writeln(pong received ,s);
sleep(dur!seconds(1));
ping.send(pong);
}
);
}
}catch(Exception e){}
}

void main() {
auto a1 = spawn(ping);
auto a2 = spawn(pong,a1);
a1.send(a2);
sleep(dur!seconds(10));
}


Re: floating-WTF - Compiler-BUG with 64bit

2012-01-24 Thread Timon Gehr

On 01/24/2012 10:28 PM, %u wrote:

Shouldn't this go into 'digitalmars.D' ?


It should go straight to the bug tracker.


Re: for loop

2012-01-23 Thread Timon Gehr

On 01/23/2012 07:06 PM, bearophile wrote:

Ellery Newcomer:


void main(){
  for ({int x=0; short y=0;} x  10; x++, y++){
  }
}


I don't understand, is that a compiler bug?
Aren't x and y in a sub-scope that ends before you use x and y?

Bye,
bearophile


It is not a bug.

ForStatement:
for (Initialize Testopt ; Incrementopt) ScopeStatement
Initialize:
;
NoScopeNonEmptyStatement

Initialize is NoScope.


Re: actors library?

2012-01-23 Thread Timon Gehr

On 01/23/2012 08:01 PM, Xan xan wrote:

Hi.

Is there any actors library in D. Spawn and etc is ok, but I want more
high-level thing and actors it's the best I get, I think.
I searched and nothing.

I'm interested in D 2.0 or 1.0. Whatever!

Thanks in advace,
Xan.


std.concurrency is an actors library.
What exactly do you mean when you say more high-level?


Re: no-argument constructor: is this a bug?

2012-01-22 Thread Timon Gehr

On 01/23/2012 12:51 AM, Caligo wrote:

struct A(uint samples){

   float[samples] _data = void;

   this(float val = 0.0f){ fill(_data[], val); }
}


   auto a = A!8();

a._data is filled with garbage instead of zeros because the
no-argument constructor is called instead of the one that I've
defined.


structs are always default-constructible, and, as a tie-breaker, a 
function definition that has the exact number of arguments is considered 
a better match one that has to supply default-arguments to match. You 
could use a static opCall to make auto a = A!8() work.


Re: Passing arguments to a new thread

2012-01-20 Thread Timon Gehr

On 01/20/2012 03:12 PM, Mars wrote:

Hello everybody.
As the title states, I want to run a function in a new thread, and pass
it some arguments. How would I do that? I guess I could make a class,
deriving from Thread, and work with it, but out of curiosity, I'd like
to know if it's possible with a simple function.

Mars


See std.concurrency.

auto tid = spawn(function, arg1, arg2, arg3, ...);


Re: Changes for newer version...

2012-01-20 Thread Timon Gehr

On 01/19/2012 09:30 PM, Era Scarecrow wrote:

  Been a bit out of it for a while, but finding enough tools at my disposal I 
feel I can work on/convert a project now.

  I happen to have one of the first printing books (without the name on the 
cover), and although it may be worth millions in a few years, apparently 
there's been enough changes that certain features are not familiar in the 
discussions.

  So I need to ask since I don't see any obvious pages that describe it. What 
are the changes to D2, since the book's release? What has externally changed? 
(Internal implementation of features need not be mentioned if it's transparent 
to the programmer and user).


The most important changes are probably:

- inout type qualifier

The type qualifier inout can be used as a wildcard to stand for any of 
mutable, const, immutable. Its meaning is automatically deduced and is 
the same throughout a certain function definition or function call.


For example:

inout(int)[] identity(inout(int)[] x){return x;}
int[] x;
immutable(int)[] y;
const(int)[] z;
static assert(is(typeof(identity(x)) == int[]));
static assert(is(typeof(identity(y)) == immutable(int)[]));
static assert(is(typeof(identity(z)) == const(int)[]));



- function local imports
void main(){
import std.stdio;
writeln(hello world!);
}


- new function/delegate literal syntax (coming DMD 2.058)

identifier = expression
or
(id1, id2) = expression
or
(type id1, type id2) = expression

import std.stdio, std.range, std.algorithm;
void main(){
writeln(some odd squares:);
writeln(map!(x=x^^2)(filter!(x=x1)(iota(1,1000;
}




Re: tdpl: function literals versus delegate lierals

2012-01-19 Thread Timon Gehr

On 01/19/2012 05:41 PM, Jerome BENOIT wrote:

Hello List:

On my box, the following D source, inspired by the subsection 5.6.1 of
tDpl,
does not work as expected:

-
// adhoc_06.d

import std.stdio;

unittest {
// Tersest, most convenient code
auto f = (int i) {};
writeln(typeid(f));
assert(is(f == function));
}

void main() {}
-

I get:

void delegate()
core.exception.AssertError@adhoc_06.d(7): unittest failure


According to the book, the assertion is true and f is a function
but not a literal.

What is going wrong ?

Thanks in advance,
Jerome


Many things, actually. You are looking at both an error in TDPL and a 
compiler bug. The compiler bug is already fixed in git head and will not 
exist in the next release. See 
http://d.puremagic.com/issues/show_bug.cgi?id=3235


In the line:

auto f = (int i) {};

f is deduced as void delegate(int) pure nothrow @safe instead of as void 
function(int) pure nothrow @safe. This is the compiler bug that has been 
fixed.



In the line:

assert(is(f == function));

TDPL contains an error. Is expressions can be used to query some 
properties of types. If an involved type is not a well-formed type the 
result is false. Since f is a variable and not a type, the is expression 
yields false. is(T == function) tests whether or not T is a function 
type. Therefore, the line should actually read is(typeof(*f)==function), 
as f is a function pointer.


I am not very happy about this particular quirk of is expressions:

void delegate() dg; // declares a delegate
void function() fp; // declares a function _pointer_

assert( is(typeof(dg) == delegate));
assert(!is(typeof(fp) == function)); // the is expression tests whether 
it is a function, not whether it is a function pointer

assert(is(typeof(*fp) == function));

You may want to use std.traits.IsFunctionPointer and 
std.traits.IsDelegate instead.




Re: Reading web pages

2012-01-19 Thread Timon Gehr

On 01/19/2012 04:30 PM, Xan xan wrote:

Hi,

I want to simply code a script to get the url as string in D 2.0.
I have this code:

//D 2.0
//gdmd-4.6
import std.stdio, std.string, std.conv, std.stream;
import std.socket, std.socketstream;

int main(string [] args)
{
 if (args.length  2) {
writeln(Usage:);
writeln(   ./aranya {url1,url2, ...});
return 0;
}
else {
foreach (a; args[1..$]) {
Socket sock = new TcpSocket(new InternetAddress(a, 80));
scope(exit) sock.close();
Stream ss = new SocketStream(sock);
ss.writeString(GET ~ a ~  HTTP/1.1\r\n);
writeln(ss);
}
return 0;
}
}


but when I use it, I receive:
$ ./aranya http://www.google.com
std.socket.AddressException@../../../src/libphobos/std/socket.d(697):
Unable to resolve host 'http://www.google.com'

What fails?

Thanks in advance,
Xan.


The protocol specification is part of the get request.

./aranaya www.google.com

seems to actually connect to google. (it still does not work fully, I 
get back 400 Bad Request, but maybe you can figure it out)


Re: Switch and break

2012-01-19 Thread Timon Gehr

On 01/19/2012 10:55 PM, RenatoL wrote:

Just curious: why in D we are not obligated to use break in every
branch of a swicth structure? That is:
switch (i)
{
case 1:
writeln(You wrote 1);
case 2:
writeln(You wrote 2);
case 3:
writeln(You wrote 3);
default:
writeln(I said: 1 or 2 or 3!);
 }

is good in D, while, for example, similar code in C# is incorrect
and if you want to play with fall through you have to make some
trick. Again this behaviour of D seems a bit buggy, to me. Are
there design reasons?


Compile with -w enabled and the compiler will complain about implicit 
fall-through. You can use goto case/goto default for explicit fall-through.


Re: Pure functions and delegates

2012-01-18 Thread Timon Gehr

On 01/18/2012 04:40 AM, H. S. Teoh wrote:

So, I was quite impressed with D's pureness system, and was
experimenting a bit with it. Then I discovered that delegates are
impure, which seems reasonable since there's no way to know what a
delegate might do. But *if* the compiler verifies that a particular
delegate is (weakly) pure in the context of the function that passed it,
then couldn't the function that it gets passed to be declared pure as
well?

The context is this:

class MyCollection {
...
void opApply(int delegate(const ref int n) cb) const {
...
if (cb(...)) { ... }
...
}
...
int[] enumerate() {
int[] list;
foreach (n; this) {
list ~= n;
}
return list;
}
}

Is there a way to convince the compiler that enumerate() can be marked
'pure' even though opApply() can't, in general, be pure because it
doesn't know what the delegate does?

Technically, enumerate() is weakly pure, because its delegate does not
touch anything outside of its scope, and given this particular delegate,
opApply() also is weakly pure. In other words, opApply()'s pureness
depends on the delegate passed to it. So if there was a way for the
compiler to check that yes, opApply() is (weakly) pure except for the
part that calls the delegate (perhaps using some kind of conditionally
pure attribute?), then it should, in theory, be possible to verify that
yes, the delegate that enumerate() passes to opApply() does not violate
pureness, so enumerate() can be labelled 'pure'.

The trouble is, given the current state of things, there is no way to
implement enumerate() in a pure way, short of duplicating most of
opApply()'s code and substituting the line that calls the delegate.
Which is a rather ugly workaround. But otherwise, MyCollection cannot be
used inside a (strongly) pure function unless it avoids using opApply()
and enumerate() altogether, even if the container never escapes the pure
function's scope. This is quite a major limitation IMHO.


T



I see two distinct issues here:

1.

int foo(int delegate(int) dg,x){return dg(x);}
int bar(int x)pure{foo(x=x,x);} // error but would be ok

2.

int foo(int x)pure{
int x;
(y=x=y)(2); // error but would be ok
return x;
}

1. could be resolved by a simple purity wildcard, in the lines of inout. 
(auto pure? =))
2. could be resolved by extending the weakly pure rule to the context 
pointer of nested functions. Nested functions and delegates would need 
to be able to be declared 'const'. (indicating that they are not allowed 
to mutate anything through the context pointer.) delegate literals and 
nested template function instantiations would need const inference.









Re: tdpl: partial ordering of functions: conflict error

2012-01-18 Thread Timon Gehr

On 01/18/2012 02:32 PM, Jerome BENOIT wrote:



On 18/01/12 04:36, Jonathan M Davis wrote:

On Wednesday, January 18, 2012 02:33:25 Jerome BENOIT wrote:

And I cannot figure why :-(


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

As a workaround, templatize the last function by changing its
signature to

int[] find()(int[] longer, int[] shorter)


actually it does not work either: gdmd gives an other error message now.


T[] find(T, E)(T[] haystack, E needle)
if (is(typeof(haystack[0] != needle) == bool)) {
while (haystack.length  0  haystack[0] != needle) {
haystack = haystack[1 .. $];
}
return haystack;
}

TL[] find(TL, TS)(TL[] longer, TS[] shorter)
if (is(typeof(longer[0 .. 1] == shorter) : bool)) {
while (longer.length = shorter.length) {
if (longer[0 .. shorter.length] == shorter) break;
longer=longer[1 .. $];
}
return longer;
}

int[] find()(int[] longer, int[] shorter) {
while (longer.length = shorter.length) {
if (longer[0 .. shorter.length] == shorter) break;
longer=longer[1 .. $];
}
return longer;
}

unittest {
// Test the introduced overloads
long[] a1 = [ 6, 1, 2, 3 ];
long[] a2 = [ 1 , 2 ];
int[] b1 = [ 6, 1, 2, 3 ];
int[] b2 = [ 1 , 2 ];
assert(find(a1, a2) == a1[1 .. $]);
assert(find(a1, b2) == a1[1 .. $]);
assert(find(b1, b2) == b1[1 .. $]);
}

void main() {}


The message is now:
searching_05.d:34: Error: template searching_05.find(T,E) if
(is(typeof(haystack[0] != needle) == bool)) find(T,E) if
(is(typeof(haystack[0] != needle) == bool)) matches more than one
template declaration, searching_05.d(9):find(TL,TS) if
(is(typeof(longer[0..1] == shorter) : bool)) and searching_05.d(18):find()

Is partial ordering really supported ?



Yes it is, and your code snippet indeed compiles on my machine. Are you 
maybe using an outdated version of the compiler?







Re: tdpl: partial ordering of functions: conflict error

2012-01-18 Thread Timon Gehr

On 01/18/2012 04:57 PM, Timon Gehr wrote:

On 01/18/2012 02:32 PM, Jerome BENOIT wrote:



On 18/01/12 04:36, Jonathan M Davis wrote:

On Wednesday, January 18, 2012 02:33:25 Jerome BENOIT wrote:

And I cannot figure why :-(


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

As a workaround, templatize the last function by changing its
signature to

int[] find()(int[] longer, int[] shorter)


actually it does not work either: gdmd gives an other error message now.


T[] find(T, E)(T[] haystack, E needle)
if (is(typeof(haystack[0] != needle) == bool)) {
while (haystack.length  0  haystack[0] != needle) {
haystack = haystack[1 .. $];
}
return haystack;
}

TL[] find(TL, TS)(TL[] longer, TS[] shorter)
if (is(typeof(longer[0 .. 1] == shorter) : bool)) {
while (longer.length = shorter.length) {
if (longer[0 .. shorter.length] == shorter) break;
longer=longer[1 .. $];
}
return longer;
}

int[] find()(int[] longer, int[] shorter) {
while (longer.length = shorter.length) {
if (longer[0 .. shorter.length] == shorter) break;
longer=longer[1 .. $];
}
return longer;
}

unittest {
// Test the introduced overloads
long[] a1 = [ 6, 1, 2, 3 ];
long[] a2 = [ 1 , 2 ];
int[] b1 = [ 6, 1, 2, 3 ];
int[] b2 = [ 1 , 2 ];
assert(find(a1, a2) == a1[1 .. $]);
assert(find(a1, b2) == a1[1 .. $]);
assert(find(b1, b2) == b1[1 .. $]);
}

void main() {}


The message is now:
searching_05.d:34: Error: template searching_05.find(T,E) if
(is(typeof(haystack[0] != needle) == bool)) find(T,E) if
(is(typeof(haystack[0] != needle) == bool)) matches more than one
template declaration, searching_05.d(9):find(TL,TS) if
(is(typeof(longer[0..1] == shorter) : bool)) and
searching_05.d(18):find()

Is partial ordering really supported ?



Yes it is, and your code snippet indeed compiles on my machine. Are you
maybe using an outdated version of the compiler?




Nevermind, I forgot to pass the -unittest switch. It indeed gives that 
error. The reason it still does not compile is that the workaround 
proposed by Jonathan has slightly different semantics than it would have 
if the compiler already supported overloading of functions against 
function templates.


If exactly one of two equally good matched functions is a templated one, 
the other one is chosen. Now that you have templated the second 
function, both are an equally good match and both are templated.


If you change the last signature to
int[] find(TL:int[], TS:int[])(TL longer, TS shorter)

It will compile. However, if TL or TS are user-defined types with an 
alias this of type int[], the semantics are still different. I think 
this bug needs special attention.








Re: tdpl: partial ordering of functions: conflict error

2012-01-18 Thread Timon Gehr

On 01/18/2012 05:40 PM, Jerome BENOIT wrote:



On 18/01/12 17:07, Timon Gehr wrote:

On 01/18/2012 04:57 PM, Timon Gehr wrote:

On 01/18/2012 02:32 PM, Jerome BENOIT wrote:



On 18/01/12 04:36, Jonathan M Davis wrote:

On Wednesday, January 18, 2012 02:33:25 Jerome BENOIT wrote:

And I cannot figure why :-(


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

As a workaround, templatize the last function by changing its
signature to

int[] find()(int[] longer, int[] shorter)


actually it does not work either: gdmd gives an other error message
now.



T[] find(T, E)(T[] haystack, E needle)
if (is(typeof(haystack[0] != needle) == bool)) {
while (haystack.length  0  haystack[0] != needle) {
haystack = haystack[1 .. $];
}
return haystack;
}

TL[] find(TL, TS)(TL[] longer, TS[] shorter)
if (is(typeof(longer[0 .. 1] == shorter) : bool)) {
while (longer.length = shorter.length) {
if (longer[0 .. shorter.length] == shorter) break;
longer=longer[1 .. $];
}
return longer;
}

int[] find()(int[] longer, int[] shorter) {
while (longer.length = shorter.length) {
if (longer[0 .. shorter.length] == shorter) break;
longer=longer[1 .. $];
}
return longer;
}

unittest {
// Test the introduced overloads
long[] a1 = [ 6, 1, 2, 3 ];
long[] a2 = [ 1 , 2 ];
int[] b1 = [ 6, 1, 2, 3 ];
int[] b2 = [ 1 , 2 ];
assert(find(a1, a2) == a1[1 .. $]);
assert(find(a1, b2) == a1[1 .. $]);
assert(find(b1, b2) == b1[1 .. $]);
}

void main() {}



The message is now:
searching_05.d:34: Error: template searching_05.find(T,E) if
(is(typeof(haystack[0] != needle) == bool)) find(T,E) if
(is(typeof(haystack[0] != needle) == bool)) matches more than one
template declaration, searching_05.d(9):find(TL,TS) if
(is(typeof(longer[0..1] == shorter) : bool)) and
searching_05.d(18):find()

Is partial ordering really supported ?



Yes it is, and your code snippet indeed compiles on my machine. Are you
maybe using an outdated version of the compiler?




Nevermind, I forgot to pass the -unittest switch. It indeed gives that
error. The reason it still does not compile is that the workaround
proposed by Jonathan has slightly different semantics than it would
have if the compiler already supported overloading of functions
against function templates.

If exactly one of two equally good matched functions is a templated
one, the other one is chosen.


So the D code in my first post may work and thus the workaround is not
necessary.



The language does not mandate the workaround, but the workaround is 
necessary until the compiler is fixed.


Re: Error: 'this' is only defined in non-static member functions, not parse

2012-01-17 Thread Timon Gehr

On 01/17/2012 06:02 PM, Matej Nanut wrote:

On 17 January 2012 16:54, H. S. Teohhst...@quickfur.ath.cx  wrote:

This may be the cause of your trouble. If the nested class references
members in the outer class, then moving it outside will break it, since
it won't have an outer scope anymore.


T

--
Only boring people get bored. -- JM


That was my guess too — but I'm not referencing the outer class. The
outer class is just using instances of the inner one. Also, the line number
of the error points to ‘new’ statements in the static method. (The calls
which instantiate subclasses of the inner class.) If I do return null it
works as well, without complaining. So it's not a referencing issue I think.

As you all seem eager to help, I will copy the entire class, without
subclasses, to here. I will be grateful for any comments regarding the
current issue at hand or about the code in general.

The ‘new’-ed Nodes are defined like ‘class CostNode : Node { ... }’.

Another note, the outer class is an inner class of another class as well,
if that makes a difference. Also, the outer class isn't really a class, it's
a struct, but renaming that to ‘class’ doesn't change anything either.

 code begin 
 class Node
 {
 static Node parse(ref string line)
 {
 string mnemonic = munch(line, A-Z);
 line = line.stripLeft();
 auto op = mnemonic in mnemonics;
 if (!op)
 throw new Exception(Unknown mnemonic: ` ~ mnemonic ~');

 final switch (*op)
 {
 case NodeType.COST:
 return new CostNode(line);
 case NodeType.PAUSE:
 return new PauseNode(line);
 case NodeType.COLDR:
 return new ColDrNode(line);
 case NodeType.COLRA:
 return new ColRaNode(line);
 case NodeType.DROP:
 return new DropNode(line);
 case NodeType.RAISE:
 return new RaiseNode(line);
 }

 /* Doing something like `return new Node()' doesn't work 
either.
  * Only `return null' works here. */
 }

 enum NodeType : ubyte
 {
 COST,
 PAUSE,
 COLDR,
 COLRA,
 DROP,
 RAISE
 }

 static immutable NodeType[string] mnemonics;
 static this()
 {
 mnemonics = [
 COST  : NodeType.COST,
 PAUSE : NodeType.PAUSE,
 COLDR : NodeType.COLDR,
 COLRA : NodeType.COLRA,
 DROP  : NodeType.DROP,
 RAISE : NodeType.RAISE
 ];
 }
 }

 code end 


I'm quite sure that the error in your code occurs for the same reason as 
in the following code snippet:


class C{
class D{}
static make(){return new D();} // error
}

You can fix it by making D static:

class C{
static class D{}
static make(){return new D();} // ok
}

The reason is that non-static inner classes have an implicit 'outer' 
property that links to the class it was created with. Therefore, to 
construct them inside a member function, the implicit 'this' pointer is 
needed. If the 'outer' property is actually unwanted, it is best to 
declare inner classes as static.


Re: Constant function/delegate literal

2012-01-17 Thread Timon Gehr

On 01/17/2012 05:02 PM, Don Clugston wrote:

On 15/01/12 20:35, Timon Gehr wrote:

On 01/14/2012 07:13 PM, Vladimir Matveev wrote:

Hi,

Is there a reason why I cannot compile the following code:

module test;

struct Test {
int delegate(int) f;
}

Test s = Test((int x) { return x + 1; });

void main(string[] args) {
return;
}

dmd 2.057 says:

test.d(7): Error: non-constant expression cast(int
delegate(int))delegate pure
nothrow @safe int(int x)
{
return x + 1;
}

?


The 'this' pointer in the delegate:
Test((int x) { return x + 1; });

is a pointer to the struct literal, which isn't constant.
You actually want it to point to variable s.



The struct literal residing in static storage has a variable address?
Why would the context pointer point to the struct literal anyway? It is 
not required.




OTOH if it were a function, it should work, but it currently doesn't.



It should even work for delegates. The context pointer would just be null.



Re: Error: 'this' is only defined in non-static member functions, not parse

2012-01-17 Thread Timon Gehr

On 01/17/2012 07:13 PM, Matej Nanut wrote:

On 17 January 2012 19:07, H. S. Teohhst...@quickfur.ath.cx  wrote:

Andrei's book (The D Programming Language) is quite thorough in
explaining these D constructs. It's a highly recommended buy if you're
doing serious work in D.


T

--
The two rules of success: 1. Don't tell everything you know. -- YHL


I've been thinking on getting that for a while now. How up to date is it?


I think it is mostly in a good state. There are a few errata and some 
unmentioned features because D is/was somewhat of a moving/improving 
target. On the other hand, many recent bug fixes were targeted at making 
the implementation consistent with the specification in TDPL.



Or does it explain such general concepts that I shouldn't be worried
about that at all?


I don't think you need to be worried, just be prepared that a few code 
samples may not compile without minimal fixes.



Everyone seems to be recommending it so I don't see
why I shouldn't get it. A free university period is also coming up, so that
might be a great way to spend my available time.



Indeed. When I read it, I have found my time well spent. It is very well 
written.



I'm definitely serious about learning and using D. I've been impressed with
it since I first saw it and I intend to do as much work with it as possible.
I'm not _doing_ any serious work with it yet, though. In fact, none of the work
I do could be considered very serious at all. :)




Re: Error: 'this' is only defined in non-static member functions, not parse

2012-01-17 Thread Timon Gehr

On 01/17/2012 06:58 PM, Matej Nanut wrote:

On 17 January 2012 18:29, Timon Gehrtimon.g...@gmx.ch  wrote:

I'm quite sure that the error in your code occurs for the same reason as in
the following code snippet:

class C{
class D{}
static make(){return new D();} // error
}

You can fix it by making D static:

class C{
static class D{}
static make(){return new D();} // ok
}

The reason is that non-static inner classes have an implicit 'outer'
property that links to the class it was created with. Therefore, to
construct them inside a member function, the implicit 'this' pointer is
needed. If the 'outer' property is actually unwanted, it is best to declare
inner classes as static.


Yes! If I move the class and its subclasses out of its outer class, and declare
them all static, it works!

Note that your `make' function is being called within class `D' in my example,
if I replace the names. However, the same thing applies.

Your explanation was nice, but now I'd like to know what the difference of a
non-static vs. a static class is, if they're defined top-level? Or are they then
the same?


Indeed they are the same. Anything top-level is implicitly static in D.


I don't expect anyone to thoroughly explain things to me, but
pointing out a good source, like a link or a book, would be really helpful.



I don't know if there is any, but I can explain to you the difference 
between static and non-static nested classes in detail:


class A{
int x;
static class B{void echo(){writeln(x);}} // n.g.
}

class A{
int x;
class B{void echo(){writeln(x);}} // ok
}

In other words, non-static nested classes can reference non-static 
fields of the enclosing class. In order to provide that functionality, 
non-static nested classes need the implicit 'outer' field. The first 
snippet is effectively rewritten to something like the following:


class A{
int x;
class B{A __outer; void echo(){writeln(__outer.x);}
}

Therefore, for constructing a class instance of type A.B, an instance of 
A must be provided as an initializer for the 'outer' field. If an 
instance of B is created in a member of A, the 'this' pointer gets used 
(and hence is required to be present), but you can also do:


void main() {
auto a = new A;
auto b = a.new B; // construct an 'A.B' with 'a' in implicit 
'outer' field

a.x = 100;
b.echo(); // writes '100'
}

This is probably one of the more obscure features of D. =)


I lack general knowledge in the OOP area and must really learn more about
it, as I've always been programming in C and could easily get away with it
as we were doing small-ish programs at university.




Re: Could assertThrown be made safe/trusted?

2012-01-17 Thread Timon Gehr

On 01/17/2012 08:21 PM, H. S. Teoh wrote:

On Tue, Jan 17, 2012 at 09:07:05AM -0800, Jonathan M Davis wrote:
[...]

Exception itself isn't @safe yet (its constructor in particular), and
I don't think that AssertError is either. A number of stuff like that
in druntime and Phobos still needs to be marked @safe or @trusted.

[...]

Just out of curiosity, why isn't it marked @safe? I looked over the
source and didn't see anything immediately obvious that would preclude
@safe.


T



The code for it was presumably written before SafeD was invented.


Re: Could assertThrown be made safe/trusted?

2012-01-17 Thread Timon Gehr

On 01/17/2012 11:31 PM, Jonathan M Davis wrote:

On Tuesday, January 17, 2012 14:14:36 H. S. Teoh wrote:

On Tue, Jan 17, 2012 at 05:04:18PM -0500, Jonathan M Davis wrote:
[...]


Attribute inferrence is a big step forward in making as much as
possible @safe and pure, but there's still plenty to do there.


[...]

Funny you should mention that, I was just starting to wonder if I should
start littering my code with 'pure', and whether it's possible to make
the compiler infer it for me. From the little that I know, it seems that
in most cases 'pure' can be automatically inferred. The compiler already
distinguishes between weakly pure and strongly pure internally, so why
not take it all the way? Not sure how this will affect inter-module
analysis, though.

But since this is apparently not yet implemented, just what *is*
implemented currently when you specify 'pure'? Common subexpression
factorization? Hoisting? Not (yet) memoization, apparently.


_pure_ is implemented. It's @safe that isn't fully implemented. pure, @safe,
and nothrow are inferred for templated functions when they're instantiated so
that they can be pure (or @safe or nothrow) based on the code that's generated
rather than always forcing it to be one or the other, since that would be far
too restrictive. But that's completely unnecessary for normal functions. You
_do_ need to mark those pure, @safe, or nothrow yourself.

If attributes were inferred for normal functions, the compiler would always
have to have the full source of every function. And even then, it might be an
instance of the halting problem. Every function is and must be pure (or @safe
or nothrow) or not when it's declared, and that's part of its signature, so it
can be known even when the full source isn't. Inference works with templates
only because they're generating code, and the compiler needs their full source
anyway.

- Jonathan M Davis


I think he is interested in the state of implementation of specific 
compiler _optimisations_ that make use of function purity in order to 
prove their correctness. IIRC ldc has CSE for pure functions, but I 
don't know exactly.


Re: lambda template literals?

2012-01-17 Thread Timon Gehr

On 01/18/2012 01:35 AM, bearophile wrote:

Is code vaguely like this meaningful and useful?


void main() {
 alias (x =  x ^^ 2) sqrTemplate;
}


Bye,
bearophile


Yes. The fact that your particular example does not work is a mere 
syntactic issue.

This works:

template ID(alias a){alias a ID;}
void main(){
alias ID!(x = x ^^ 2) sqrTemplate;
}



Re: output minimal .di files?

2012-01-16 Thread Timon Gehr

On 01/16/2012 09:40 PM, H. S. Teoh wrote:

On Mon, Jan 16, 2012 at 09:32:57PM +0100, Alex Rønne Petersen wrote:
[...]

I... don't think the error messages from expanding raw object code
would be very pleasant to read, if you used a template incorrectly...

[...]

It doesn't have to be *executable* object code; the compiler may store
extra info (perhaps as debugging data?) so that it can generate nicer
error messages.

But like I said, this assumes the compiler is allowed to store arbitrary
data inside object files, which may not be the case on some platforms.


T



How would your proposal help hiding implementation details of templates 
anyway? All information still needs to be stored. Anyone could write a 
object file - source file compiler for template implementations.


Re: Error: 'this' is only defined in non-static member functions, not parse

2012-01-16 Thread Timon Gehr

On 01/17/2012 12:49 AM, Matej Nanut wrote:

Hey everyone,

I, once again, have a problem with an error I can't seem to figure out!

The situation:
- a class, inherited by five other classes;
- the class having a static function which returns one
   if its subclasses depending on the input of a string.

Something like this:

class Node
{
   static Node parse(ref string s)
   {
 /* Get value to switch by, an enum. */
 auto switchable = /* ... */;
 final switch (switchable)
 {
   case Blah.one: return new OneNode(s);
   case Blah.two: return new TwoNode(s);
 /* ... */
 }
   }
}

And I get the mentioned error. I don't understand it:
is it saying I'm using `this' in a static member function
called `parse'? Am I insane; where am I referencing it?

The other classes are in this form:

class OneNode : Node
{
   /* ... stuff ... */
   this(ref string s)
   {
 /* Does stuff with `s'. */
   }
}

Do you need more information?

Yes; It is extremely hard to solve the problem when there is no code 
snippet given which exhibits the problematic behavior in question.




Re: Fixed matrix rows joining

2012-01-15 Thread Timon Gehr

On 01/15/2012 02:38 AM, bearophile wrote:

If I have a simple fixed-size matrix and I need to linearize (flatten) it, the 
function join() seems to not not work:


import std.array: join;
void main() {
 int[4][4] table;
 join(table);
}


test.d(4): Error: template std.array.join(RoR,R) if (isInputRange!(RoR)  
isInputRange!(ElementType!(RoR))  isForwardRange!(R)  
is(Unqual!(ElementType!(ElementType!(RoR))) == Unqual!(ElementType!(R does not match any function 
template declaration
test.d(4): Error: template std.array.join(RoR,R) if (isInputRange!(RoR)  
isInputRange!(ElementType!(RoR))  isForwardRange!(R)  
is(Unqual!(ElementType!(ElementType!(RoR))) == Unqual!(ElementType!(R cannot deduce template 
function from argument types !()(int[4u][4u])


This too doesn't work:
join(table[]);



This compiles:
join(map!q{ a[] }(table[]));


But this program shows there is something wrong (I know what's wrong), it 
prints:
[6, 4219787, 4, 6, 4219787, 4]


import std.stdio: writeln;
import std.algorithm: map;
import std.array: join;
void main() {
 int[3][2] table = [[1,2,3],[4,5,6]];
 int[] result = join(map!q{ a[] }(table[]));
 writeln(result);
}



This prints the right output, but it allocates lot of memory:
[1, 2, 3, 4, 5, 6]


import std.stdio: writeln;
import std.algorithm: map;
import std.array: join;
void main() {
 int[3][2] table = [[1,2,3],[4,5,6]];
 int[] result2 = join(map!q{ a.dup }(table[]));
 writeln(result2);
}


Do you have better suggestions?


join(map!((int[] a)=a)(table[]))

although I'd like

join(map!((ref a)=a[])(table[]))

to work. I'll file an enhancement.


Is the function join() worth fixing/changing to improve this use case?

Bye,
bearophile




Re: Constant function/delegate literal

2012-01-15 Thread Timon Gehr

On 01/14/2012 07:13 PM, Vladimir Matveev wrote:

Hi,

Is there a reason why I cannot compile the following code:

module test;

struct Test {
 int delegate(int) f;
}

Test s = Test((int x) { return x + 1; });

void main(string[] args) {
 return;
}

dmd 2.057 says:

test.d(7): Error: non-constant expression cast(int delegate(int))delegate pure
nothrow @safe int(int x)
{
return x + 1;
}

?

This is simple example; what I want to do is to create a global variable
containing a structure with some ad-hoc defined functions. The compiler
complains that it cannot evaluate  at compile time. I think this could
be solved by defining a function returning needed structure, but I think this
is cumbersome and inconvenient.

Best regards,
Vladimir Matveev.


I think it should work. I have filed a bug report:
http://d.puremagic.com/issues/show_bug.cgi?id=7298




Re: Get name of enum val at compile-time?

2012-01-15 Thread Timon Gehr

On 01/15/2012 10:02 PM, Nick Sabalausky wrote:

Timon Gehrtimon.g...@gmx.ch  wrote in message
news:jevefv$2je6$1...@digitalmars.com...

On 01/15/2012 09:34 PM, Nick Sabalausky wrote:

import std.conv;
enum Foo { hello }
enum x = to!string();



enum x = to!string(Foo.hello);


Goddamnnit, what the fuck is wrong with me? Yes that works :)




I suspect a better error message would have prevented this.
DMD still has some potential of improvement in that area. =)


Re: Absolute beginner

2012-01-13 Thread Timon Gehr

On 01/13/2012 10:34 PM, Jorge wrote:

Thanks for your answer but:

import std.stdio;
import std.conv;
void main()
{
write(Insert number: );
string s = readln();
auto i = to!int(s);
}

compiles but after i enter a number and press the enter key i get:

std.conv.ConvException@.\..\..\src\phobos\std\conv.d(1595): Can't
convert value
`
' of type string to type int

41DECC
41DD43
4027F3
402475
402D6C
402DB0
4029A7
4BBA79


what's wrong?


readln() includes the trailing newline character in the resulting 
string. You can use std.string.strip to remove leading and trailing 
whitespace:


import std.stdio;
import std.conv;
import std.string;
void main()
{
write(Insert number: );
string s = readln();
auto i = to!int(strip(s));
}


Re: About implicit array cast

2012-01-12 Thread Timon Gehr

On 01/13/2012 02:19 AM, bearophile wrote:

This code compiles, because the [0,0] dynamic array literal casts implicitly to 
int[2]:


int[2] foo() {
 return [0, 0]; // OK
}
void main() {}


And of course this too compiles:


int[2] bar() {
 int[2] ab;
 return (true) ? ab : ab; // OK
}
void main() {}



But currently this code doesn't compile:


int[2] spam() {
 int[2] ab;
 return (true) ? ab : [0, 0]; // Error
}
void main() {}


test.d(3): Error: cannot implicitly convert expression (cast(int[])ab) of type 
int[] to int[2u]


Is this good?

Bye,
bearophile


This is a bug.


Re: Mixin on a bunch of foreach fails.

2012-01-12 Thread Timon Gehr

On 01/13/2012 05:07 AM, Charles McAnany (dlang) wrote:

Hi, all. So I'm trying to make some very ugly code generic. The main
ugliness isn't in the code shape, it's in the running time. It's O(n^m)
Eww! (don't worry, n is only about 6.)

Anyhoo, Here's what I want:

void foo(int size)(int[] arr){
mixin(forStart!(size));
doStuff(pos0, pos1, pos2,...); // this line is generated by another
mixin that works correctly.
}

//Generates for loop headers.
private static string forStart( int sz)(){
string forStrings = ;
for(int i = 0; i  sz; i++){
forStrings ~=foreach(pos~text(i)~; 0..arr.length)\n ;
}
return forStrings;
}

It is my great displeasure to report:
src\hw06.d(35): found 'EOF' instead of statement
src\hw06.d(18): Error: template instance hw06.tryCombinations!(5) error
instantiating

But here's the wacky part:
I can execute this function and print it to stdout. If I do, I get...
foreach(pos0; 0..arr.length)
foreach(pos1; 0..arr.length)
foreach(pos2; 0..arr.length)
foreach(pos3; 0..arr.length)
foreach(pos4; 0..arr.length)

and I can copy-paste this exact code into where I currently have the
mixin, and the code behaves correctly.

Is there some subtle aspect of mixin that I'm missing here?

Cheers,
Charles.


Yes. You can only mixin whole statements or expressions. The easiest way 
to fix your code is to join the two mixins into one using the 
concatenation operator. Eg: mixin(forStart!(size)~generateDoStuff(...));


By the way, you can make the code more clean by making 'int sz' a simple 
function parameter. (static string forStart(int sz){...})






Re: Compile-time evaluation of real expressions?

2012-01-06 Thread Timon Gehr

On 01/07/2012 12:37 AM, Jonathan M Davis wrote:

On Saturday, January 07, 2012 00:03:39 Alex Rønne Petersen wrote:

Most likely those functions are just implemented using inline assembly,
therefore not usable in CTFE.


Yeah, several functions in std.math use inline assembly. So, for them to be
able to be used at compile time, either the compiler must be expanded to be
able to run asm statements at compile time (which may or may not be planned
and may or may not be reasonable), or those functions need another branch
(using __cfte in an if condition) which doesn't use assembly. Or I suppose
that if the extra check for __ctfe isn't considered particularly acceptable
(after all, they're already using assembly)  [snip.]


If the if condition is a constant, there is no runtime overhead.


Re: Problem with Hiredis Binding

2012-01-05 Thread Timon Gehr

On 01/05/2012 07:14 PM, Joshua Reusch wrote:

Am 05.01.2012 17:21, schrieb Puming Zhao:

Hi, I'm new in D programming, and does not have much C experience
either. After
reading TDPL book and playing with some sample codes, I came to decide
to try
something more `practical`. I began with a Redis client binding from
Hiredis C code.
Hiredis is a small lib, and seems very simple to bind to D.

My code on github:

https://github.com/zhaopuming/dredis

But I went into problems that I don't know how to solve. When running
example.d I
went into segment fault, and can't get redisReply from a redis
command. I tried to
google it but got nothing.

So my question is, could some one with more knowledge in redis or C/D
look into my
code and see what's wrong ? Or is there already a Redis binding exists?


dredis.d:
  redisContext* redisConnectWithTimeout(const char* ip, int port,
timeval tv);

example.d:
  redisConnectWithTimeout(127.0.0.1, 6379, timeout);


D strings do not end with an \0 byte !
You can use std.string.toStringz to convert them to C's const char*

-- Joshua


D string literals are zero-terminated.


Re: out default argument of void

2012-01-04 Thread Timon Gehr

On 01/04/2012 11:19 PM, Caligo wrote:

I have a function that looks something like this:

bool fun(double theta, out A a, out B b, out C c){  /* ... */ }

if fun() returns false, then nothing is supposed to be assigned to a,
b, c.  If it returns true, then values are assigned to a, b, c.  Also,
there are two ways to call fun():  If I'm interested in the return
value only, then

1. fun(theta);

otherwise,

2. fun(theta, a, b, c);

Obviously, method #1 won't work because there is no such thing as:

bool fun(double theta, out A a = void, out B b = void, out C c =
void){  /* ... */ }

is there?

So, I have to lose 'out' and use pointers instead:

bool fun(double theta, A* a = null, B* b = null, C* c = null){  /* ... */ }

I don't want to use a variadic function for this either because it's
not really a variadic function.

1. Are there any other solutions ?


Yes. Use overloading.

This would work:

bool fun(double theta, out A a, out B b, out C c){  /* ... */ }
bool fun(double theta){
A a; B b; C c;
return fun(theta,a,b,c);
}

Or this:

private bool funImpl(double theta, A* a = null, B* b = null, C* c = 
null){  /* ... */ }


bool fun(double theta, out A a, out B b, out C c){return 
funImpl(theta,a,b,c);

bool fun(double theta){return funImpl(theta);}



2. Would it make sense to have 'out default argument of void' in D?


void initializer means uninitialized. I don't think that can do what you 
want.


Re: Using in with associative arrays and then indexing them (efficiency)

2012-01-03 Thread Timon Gehr

On 01/03/2012 12:07 PM, Jonathan M Davis wrote:

On Tuesday, January 03, 2012 11:52:13 Matej Nanut wrote:

Hello everyone,

I would like to know whether

 if (symbol in symbols)
 return symbols[symbol];

is any less efficient than

 auto tmp = symbol in symbols;
 if (tmp !is null)
 return *tmp;

Without optimisation, it looks like the first example
searches for `symbol' twice.


Of course it does. in does a search and returns a pointer to the element in
the AA (or null if it isn't there). The subscript operator also does a search,
returning the element if it's there and blowing up if it's not
(OutOfRangeError IIRC without -release and who-knows-what with -release). So,
if you use in and then the subscript operator, of course it's going to search
twice. Part of the point of using in is to not have to do a double lookup
(like you would be doing if AAs had a contains function and you called that
prior to using the substript operator).

The correct way to do it is the second way, though you should be able to
reduce it to

if(auto tmp = symbol in symbols)
 return *tmp;

- Jonathan M Davis


I think this is the single most ugly thing in the language. IIRC ldc 
will generate identical code for both code snippets.


Re: Using in with associative arrays and then indexing them (efficiency)

2012-01-03 Thread Timon Gehr

On 01/03/2012 12:22 PM, Jonathan M Davis wrote:

On Tuesday, January 03, 2012 12:13:45 Timon Gehr wrote:

On 01/03/2012 12:07 PM, Jonathan M Davis wrote:

On Tuesday, January 03, 2012 11:52:13 Matej Nanut wrote:

Hello everyone,

I would like to know whether

  if (symbol in symbols)

  return symbols[symbol];

is any less efficient than

  auto tmp = symbol in symbols;
  if (tmp !is null)

  return *tmp;

Without optimisation, it looks like the first example
searches for `symbol' twice.


Of course it does. in does a search and returns a pointer to the element
in the AA (or null if it isn't there). The subscript operator also does
a search, returning the element if it's there and blowing up if it's
not
(OutOfRangeError IIRC without -release and who-knows-what with
-release). So, if you use in and then the subscript operator, of course
it's going to search twice. Part of the point of using in is to not
have to do a double lookup (like you would be doing if AAs had a
contains function and you called that prior to using the substript
operator).

The correct way to do it is the second way, though you should be able to
reduce it to

if(auto tmp = symbol in symbols)

  return *tmp;

- Jonathan M Davis


I think this is the single most ugly thing in the language. IIRC ldc
will generate identical code for both code snippets.


What, declaring variables in if statements? It's fantastic IMHO. It allows you
to restrict the scope of the variable to the if statement's scope and still
use it in the if's condition. And yes, as far as the assembly goes, the
generated code is identical. But the scoping for the variable is most
definitely different - it won't exist past the if statement if it's declared in
the if's condition - and it saves you a line of code. The reduced scope is the
more important of the two though IMHO, as nice as saving a line of code is.

- Jonathan M Davis


No, I love declaring variables in if statements and would like it to be 
extended to while statements as well. What I meant is the fact that 
something called 'in' returns a pointer. And the two code snippets I was 
referring to were the two in Matej's post.


Re: opCast!bool

2012-01-03 Thread Timon Gehr

On 01/04/2012 12:31 AM, Jonathan M Davis wrote:

On Tuesday, January 03, 2012 17:41:12 simendsjo wrote:

I guess this is as designed, but I'll ask anyway.

http://dlang.org/operatoroverloading.html#Cast says an expression is
rewritten to opCast whenever a bool result is expected.

This is true for
if(e) somethingElse
and e  somethingElse

, but not for other parts.
assert(cast(bool)e == true); // explicit cast works
assert(e == true); // Error: incompatible types for ((s) == (false)):
'S' and 'bool'

is(typeof(e) : bool); // false


Yeah. It's the same for built-in types. Take arrays and pointers for example.
They don't implicitly convert to bool, but when you use them in a condition,
they implicitly convert to bool (true if they're non-null, false if they're
null). If you want implicit conversion in general, then you need to use alias
this.

- Jonathan M Davis


The conversion is explicit. if(x) is rewritten to if(cast(bool)x) and e 
 somethingElse is rewritten to cast(bool)e  cast(bool)somethingElse.


Re: opCast!bool

2012-01-03 Thread Timon Gehr

On 01/03/2012 05:41 PM, simendsjo wrote:

I guess this is as designed, but I'll ask anyway.

http://dlang.org/operatoroverloading.html#Cast says an expression is
rewritten to opCast whenever a bool result is expected.

This is true for
if(e) somethingElse
and e  somethingElse

, but not for other parts.
assert(cast(bool)e == true); // explicit cast works
assert(e == true); // Error: incompatible types for ((s) == (false)):
'S' and 'bool'


There is no 'bool result expected': The relation of the two operands in 
== is symmetric. You could just as well say that the result of 'true' is 
expected to be of type typeof(e).





is(typeof(e) : bool); // false


This tests whether or not typeof(e) implicitly converts to bool, which 
can be false even if an explicit cast would succeed.


Re: rvalue references template ?

2012-01-02 Thread Timon Gehr

On 01/02/2012 03:02 PM, Joshua Reusch wrote:

Is it possible to create a template turning any value into a lvalue?
This would be helpful if a function expects a reference but you dont
need the result of the change:

///decode(S)(in S str, ref size_t index);
auto c = std.utf.decode(some_string, lval!0);


Yes, but I currently cannot see a full solution that does not heap-allocate.


Re: Array of array

2012-01-02 Thread Timon Gehr

On 01/02/2012 11:04 PM, RenatoL wrote:

auto r = new int[][5];
this is ok

auto r = new int[][];
this is not ok
Error: new can only create structs, dynamic arrays or class objects
, not int[][]'s

why?


What would you expect the code to do?
What you are trying to achieve is similar to:

class Array(T){this(size_t length){...}}
auto r = new Array!(Array!int); // error: missing constructor argument


Re: Array of array

2012-01-02 Thread Timon Gehr

On 01/02/2012 11:21 PM, RenatoL wrote:

Just curious... the answer of the compiler it's a bit unclear to
me...

T[] is a dynamic array of type T.
T[][] is a dynamic array of T[]. But this doesn't work. Why?


It does work. Why do you think it does not?

T[] a;   // ok
T[][] b; // ok
auto c = new T[5];   // ok
auto d = new T[][5]; // ok
auto e = new T[];// fail, nonsensical
auto f = new T[][];  // fail, nonsensical



Re: Array of array

2012-01-02 Thread Timon Gehr

On 01/03/2012 12:03 AM, RenatoL wrote:

I have:

auto r = new int[][];

Error: new can only create structs, dynamic arrays or class objects
, not int[][]'s

while

auto r = new int[][3];

is ok.


new int[][3] is an alternate form of new int[][](3); new int[][3] 
allocates an int[][] with 3 default-initialized elements.


Re: Hole of new? (Re: Array of array)

2012-01-02 Thread Timon Gehr

On 01/03/2012 12:02 AM, Mafi wrote:

Am 02.01.2012 23:33, schrieb Timon Gehr:

On 01/02/2012 11:21 PM, RenatoL wrote:

Just curious... the answer of the compiler it's a bit unclear to
me...

T[] is a dynamic array of type T.
T[][] is a dynamic array of T[]. But this doesn't work. Why?


It does work. Why do you think it does not?

T[] a; // ok
T[][] b; // ok
auto c = new T[5]; // ok
auto d = new T[][5]; // ok
auto e = new T[]; // fail, nonsensical
auto f = new T[][]; // fail, nonsensical



Here we come to an interesting point I often thought of. How do you
allocate a T[] itself (so you get a T[]*) or a ClassType reference (so
you get a ClassType*) on the heap (without casting)?
As far as I know it's not possible with new.
new T[n] is of type T[].
new T[]* is of type T[]**.
new ClassType is of type ClassType.
new ClassType* is of type ClassType**.

Is this a Hole of new?

Mafi


Yes, but you can use (new T[][1]).ptr; to allocate T[] itself (and get a 
T[]*). Maybe new T[] should be interpreted as allocating a T[] and give 
back a T[]*.


Re: Array of array

2012-01-02 Thread Timon Gehr

On 01/03/2012 12:46 AM, Matej Nanut wrote:



On 3 January 2012 00:27, Timon Gehr timon.g...@gmx.ch
mailto:timon.g...@gmx.ch wrote:

On 01/03/2012 12:03 AM, RenatoL wrote:

I have:

auto r = new int[][];

Error: new can only create structs, dynamic arrays or class objects
, not int[][]'s

while

auto r = new int[][3];

is ok.


new int[][3] is an alternate form of new int[][](3); new int[][3]
allocates an int[][] with 3 default-initialized elements.


I assume `int[][] sth;` does what RenatoL wants to accomplish by `auto
sth = new int[][];`. I do however have a question:
is `auto sth = new int[][5];` the same as `int[][5] sth;`? If not, what
is the difference?



It is not the same thing.

First of all, lets get rid of int[][] and use int[] for further reasoning.

int[] is a data structure with two members: 'ptr' and 'length'. 'ptr' is 
a pointer to the first element of the array, and 'length' indicates how 
many elements are in the array. int[] does not carry any data on its 
own: it is only a reference to the data.


int[5] on the other hand is a data structure that contains 5 integers 
with the indices 0,1,2,3,4.



|ptr|length| - int[]

|0|1|2|3|4| - int[5]

An int[5] can be sliced to get an int[]:

void main(){
int[5] arr1=[0,1,2,3,4];
int[] arr2 = arr1[];
// arr2 is now a reference to arr1's data:
assert(arr2.ptr is arr1[0]  arr2.length == 5);
// changing arr2 changes arr1:
arr2[0] = 5;
assert(arr1 == [5,1,2,3,4]);
// assigning int[5] to int[5] copies the data
int[5] arr3 = arr1;
assert(arr2.ptr !is arr1[0]);
// therefore, changing arr3 lets arr1 intact
arr3[0] = 0;
assert(arr1 == [5,1,2,3,4]);
}



void main(){
int[] arr1; // creates an int[] on the stack with ptr=null and length=0
int[5] arr2; // creates in int[5] on the stack with arr2[i]=0 for i 
in 0,1,2,3,4

arr1 = arr2[]; // array slice lets arr1 reference the data of arr2
arr1 = new int[](5); // allocates an int[5] on the heap and lets 
arr1 reference the newly created data
arr1 = new int[5]; // same as the above, syntax carried over from 
C++/Java

}

With this in mind, it is now possible to understand the difference 
between int[][5] sth and auto sth = new int[][5]:


void main(){
   int[][5] sth1; // creates an int[][5] on the stack (5 
default-initialized int[]s)
   auto sth2 = new int[][5]; // creates an int[][5] on the heap and 
lets sth2 reference it.

}






Re: do-while loops

2011-12-28 Thread Timon Gehr

On 12/28/2011 02:29 PM, bearophile wrote:

One thing that I often find not handy in the design of do-while loops: the scope of their 
body ends before the while:


void main() {
 do {
 int x = 5;
 } while (x != 5); // Error: undefined identifier x
}


So I can't define inside them variables that I test in the while().

This keeps the scope clean, but it's not nice looking:


void main() {
 {
 int x;
 do {
 x = 5;
 } while (x != 5);
 }
}

Bye,
bearophile


I fully agree, but why does this go to D.learn?


Re: do-while loops

2011-12-28 Thread Timon Gehr

On 12/28/2011 04:01 PM, Andrej Mitrovic wrote:

A very small cheat:
void main()
{
 if (int x = 0)
 do {
 x = 5;
 } while (x != 5);
}

Only works for this simple case though. Put your post in d.general, I
totally agree with it as well.


This won't work. The 'if' condition is always false.


Re: do-while loops

2011-12-28 Thread Timon Gehr

On 12/28/2011 06:42 PM, bearophile wrote:

Timon Gehr:


I fully agree, but why does this go to D.learn?


Because I think there's no hope to see this situation changed :-)

Bye,
bearophile


Why? The only D code that would get broken would be code that uses a 
global variable in the loop condition of the same name as a do loop 
local variable.


Re: do-while loops

2011-12-28 Thread Timon Gehr

On 12/28/2011 09:32 PM, Alex Rønne Petersen wrote:

On 28-12-2011 18:50, Timon Gehr wrote:

On 12/28/2011 06:42 PM, bearophile wrote:

Timon Gehr:


I fully agree, but why does this go to D.learn?


Because I think there's no hope to see this situation changed :-)

Bye,
bearophile


Why? The only D code that would get broken would be code that uses a
global variable in the loop condition of the same name as a do loop
local variable.


That's still a bit of a risk to take for such a small change, IMHO.

- Alex


Well, do loops are the least frequently used looping constructs. Also, 
if you actually have code like the following


import foo; // defines global symbol 'x'

void main(){
do {
int x;
// ...
}while(x2);
}


It is likely that it is actually buggy because the programmer assumed 
lookup would work differently.


Re: do-while loops

2011-12-28 Thread Timon Gehr

On 12/28/2011 10:45 PM, Manfred Nowak wrote:

bearophile wrote:


void main() {
 do {
 int x = 5;
 } while (x != 5); // Error: undefined identifier x
}



Do you mean, that the similar while-loop should also be okay?

| void main() {
| while (x != 5) /* uses `x' out of _following_ scope */ {
| int x = 5;
| };
| }

-manfred


No, it is not any more valid than the following code, even if condition 
and body are scoped together:


void main() {
bool _ = x != 5;
int x = 5;
}

Related:

https://github.com/D-Programming-Language/dmd/pull/342#issuecomment-3232150


Re: Reading about D: few questions

2011-12-24 Thread Timon Gehr

On 12/24/2011 02:02 AM, Jonathan M Davis wrote:

The core problem for a number of these situations is how types are handled
with regards to expressions. In an expression such as

char[] arr = s ~ '.';

the type of the value being assigned is determined _before_ the assignment is
done. So, even though in theory the compiler could make it work, it doesn't,
because by the time it's looking at the type being assigned to, it's too late.
There would need to be a fundamental change in how the language functions in
order to fix issues like this.


Examples of resolved issues like this:

int[] foo()pure;
immutable(int)[] x = foo;




pure can do it when it can not because it's able to look at what the return
type is and changing the result of the expression accordingly but because it
has guarantees which make it so that it knows that the return value could be
converted to any level of constness and still be valid. The types used in the
expressions internally are generally irrelevant.

So, while I completely agree that it would be an improvement if the compiler
did a better job with implicit conversion when it could theoretically be done,
I'm not sure how much of that we're actually going to end up seeing simply
because of how the language and type system works in terms of the order of
evaluation.

- Jonathan M Davis


I don't think this is very hard to get working.


Re: Reading about D: few questions

2011-12-24 Thread Timon Gehr

On 12/24/2011 07:00 PM, Andrew Wiley wrote:

On Sat, Dec 24, 2011 at 9:50 AM, Timon Gehrtimon.g...@gmx.ch  wrote:

On 12/24/2011 06:18 PM, Andrew Wiley wrote:


2011/12/24 Mr. Anonymousmailnew4s...@gmail.com:


On 24.12.2011 19:01, Denis Shelomovskij wrote:



23.12.2011 22:51, bearophile пишет:



++a[] works, but a[]++ doesn't.



Already known compiler bug.




Is it a joke? Array expression in D are for performance reasons to
generate x2-x100 faster code without any compiler optimisations. Link to
one of these epic comments (even x100 more epic because of '%' use
instead of 'x###'):


https://github.com/D-Programming-Language/druntime/blob/master/src/rt/arraybyte.d#L1127


But `a[]++` should store a copy of `a`, increment elements and return
stored copy. It is hidden GC allocation. We already have a silent
allocation in closures, but here a _really large_ peace of data can be
allocated. Yes, this allocation sometimes can be optimized out but not
always.

IMHO, D should not have `a[]++` operator.




Why should it store a copy? o_O
I also don't see any allocations in the code on the URL above.



int a_orig = a++;
int[] arr_orig = arr[]++;

If ++ is going to be applied to an array, it needs to have the same
meaning as it does elsewhere. After this operation, arr_orig and arr
must refer to different arrays for that to be true.



Not necessarily.

class D{
int payload;
D opUnary(string op:++)(){payload++; return this;}
}

void main() {
D d = new D;
assert(d.payload == 0);
assert(d++.payload == 1);
}


That doesn't match integer semantics:
int a = 0;
assert(a++ == 0);
assert(a == 1);


Yes, that was my point.



Re: Reading about D: few questions

2011-12-24 Thread Timon Gehr

On 12/24/2011 08:41 PM, Mr. Anonymous wrote:

On 24.12.2011 21:22, Andrew Wiley wrote:

On Sat, Dec 24, 2011 at 1:08 PM, Timon Gehrtimon.g...@gmx.ch wrote:

On 12/24/2011 07:00 PM, Andrew Wiley wrote:


On Sat, Dec 24, 2011 at 9:50 AM, Timon Gehrtimon.g...@gmx.ch wrote:


On 12/24/2011 06:18 PM, Andrew Wiley wrote:



2011/12/24 Mr. Anonymousmailnew4s...@gmail.com:


On 24.12.2011 19:01, Denis Shelomovskij wrote:




23.12.2011 22:51, bearophile пишет:




++a[] works, but a[]++ doesn't.




Already known compiler bug.





Is it a joke? Array expression in D are for performance reasons to
generate x2-x100 faster code without any compiler optimisations.
Link
to
one of these epic comments (even x100 more epic because of '%' use
instead of 'x###'):



https://github.com/D-Programming-Language/druntime/blob/master/src/rt/arraybyte.d#L1127



But `a[]++` should store a copy of `a`, increment elements and
return
stored copy. It is hidden GC allocation. We already have a silent
allocation in closures, but here a _really large_ peace of data
can be
allocated. Yes, this allocation sometimes can be optimized out
but not
always.

IMHO, D should not have `a[]++` operator.





Why should it store a copy? o_O
I also don't see any allocations in the code on the URL above.




int a_orig = a++;
int[] arr_orig = arr[]++;

If ++ is going to be applied to an array, it needs to have the same
meaning as it does elsewhere. After this operation, arr_orig and arr
must refer to different arrays for that to be true.




Not necessarily.

class D{
int payload;
D opUnary(string op:++)(){payload++; return this;}
}

void main() {
D d = new D;
assert(d.payload == 0);
assert(d++.payload == 1);
}



That doesn't match integer semantics:
int a = 0;
assert(a++ == 0);
assert(a == 1);



Yes, that was my point.



Then I'm not understanding what you're trying to prove.
I'm saying that if we implement a postfix ++ operator for arrays,
keeping the language consistent would require it to make a copy if the
user stores a copy of the original array. I guess it could be argued
that since arrays have hybrid value/reference semantics, no copy
should be made and the original should change.

Actually, looking at it from that angle, a[]++ is fundamentally
ambiguous because it could have value semantics or reference
semantics, so I would argue that we shouldn't have it for that reason.
'++a' and 'a += 1' do not have such ambiguities.


Maybe you're right, but a[]++; alone, imo, should compile.


+1.


Re: Reading about D: few questions

2011-12-24 Thread Timon Gehr

On 12/24/2011 08:22 PM, Andrew Wiley wrote:

On Sat, Dec 24, 2011 at 1:08 PM, Timon Gehrtimon.g...@gmx.ch  wrote:

On 12/24/2011 07:00 PM, Andrew Wiley wrote:


On Sat, Dec 24, 2011 at 9:50 AM, Timon Gehrtimon.g...@gmx.chwrote:


On 12/24/2011 06:18 PM, Andrew Wiley wrote:



2011/12/24 Mr. Anonymousmailnew4s...@gmail.com:


On 24.12.2011 19:01, Denis Shelomovskij wrote:




23.12.2011 22:51, bearophile пишет:




++a[] works, but a[]++ doesn't.




Already known compiler bug.





Is it a joke? Array expression in D are for performance reasons to
generate x2-x100 faster code without any compiler optimisations. Link
to
one of these epic comments (even x100 more epic because of '%' use
instead of 'x###'):



https://github.com/D-Programming-Language/druntime/blob/master/src/rt/arraybyte.d#L1127


But `a[]++` should store a copy of `a`, increment elements and return
stored copy. It is hidden GC allocation. We already have a silent
allocation in closures, but here a _really large_ peace of data can be
allocated. Yes, this allocation sometimes can be optimized out but not
always.

IMHO, D should not have `a[]++` operator.





Why should it store a copy? o_O
I also don't see any allocations in the code on the URL above.




int a_orig = a++;
int[] arr_orig = arr[]++;

If ++ is going to be applied to an array, it needs to have the same
meaning as it does elsewhere. After this operation, arr_orig and arr
must refer to different arrays for that to be true.




Not necessarily.

class D{
int payload;
D opUnary(string op:++)(){payload++; return this;}
}

void main() {
D d = new D;
assert(d.payload == 0);
assert(d++.payload == 1);
}



That doesn't match integer semantics:
int a = 0;
assert(a++ == 0);
assert(a == 1);



Yes, that was my point.



Then I'm not understanding what you're trying to prove.
I'm saying that if we implement a postfix ++ operator for arrays,
keeping the language consistent would require it to make a copy if the
user stores a copy of the original array.


And I said: not necessarily

That is because reference types have had semantics that go well with not 
making a copy all along, so there is no danger of making things more 
inconsistent.



I guess it could be argued
that since arrays have hybrid value/reference semantics, no copy
should be made and the original should change.

Actually, looking at it from that angle, a[]++ is fundamentally
ambiguous because it could have value semantics or reference
semantics, so I would argue that we shouldn't have it for that reason.
'++a' and 'a += 1' do not have such ambiguities.


I don't think a[]++ should necessarily be there either.





Re: Function overload with template alias error

2011-12-24 Thread Timon Gehr

On 12/24/2011 11:23 AM, André Stein wrote:

Hi,

I'm trying to write a template function which takes a templated alias to
another type:

struct test(T)
{
}

template aliasT(T)
{
alias test!(T) aliasT;
}

void foo(T)(test!T t) { // works
}

void foo2(T)(aliasT!T t) { // doesn't work
}

int main(string[] args)
{
test!(int) t;
aliasT!(int) t2;
foo(t);
foo2(t2); // error
return 0;
}


When foo2(t2) is called which takes an alias to test!T as argument I get
the following error from dmd:

*(21): Error: template variant.foo2(T) does not match any function
template declaration
*(21): Error: template variant.foo2(T) cannot deduce template function
from argument types !()(test!(int))

I thought that aliasT!T and test!T have the same internal types and the
compiler would be able deduce the template parameters. Am I missing
something or is this a bug in DMD? This is a reduced test case from a
piece of code where I tried to write an templated overload to
std.variant.Algebraic.

Thanks,
André


IFTI can only deduce template parameters for symbols that are defined 
inside the template instantiation because then the symbol remembers the 
template parameters. IFTI cannot reverse-instantiate templates.





Re: test if object is instance of class at compile time

2011-12-22 Thread Timon Gehr

On 12/21/2011 09:15 PM, Elvis Maehren wrote:

This works fine at runtime, but explodes in CTFE:
---
bool isInstanceOf(T, O)(O o) {
return (cast(T) o) !is null;
}
---

CTFE doesn't like !is null (cannot compare [...] at compile time).



This will be fixed in the next release:

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


Moreover, in CTFE a failed cast terminates the interpretation (cannot
reinterpret class from [...] to [...] at compile time).


I don't think this is filed already. Maybe you want to file a bug report?


Is this somehow
catchable? If so, I could do something along these lines:
---
if(__ctfe) {
try {
auto t = cast(T) o;
return true;
} catch {
return false;
}
}
---



use traits(__compiles, {...}), where '...' is the exact code that fails. 
But that is a mere workaround. What you are doing should/will work.


Re: ctfe bug?

2011-12-22 Thread Timon Gehr

On 12/22/2011 10:28 AM, Jacob Carlborg wrote:

On 2011-12-22 08:47, Johannes Pfau wrote:

Hi,
the following code is reduced from a parser generated with Ragel
(http://www.complang.org/ragel/). That's also the reason why it's
using pointers instead of array access, but Ragel guarantees that there
won't be any out-of-bound reads.

AFAIK pointers are supported in CTFE now as long as they're pointing
to an
array and there are no out-of-bounds reads. Still, the following code
fails:


ubyte[4] testCTFE()
{
ubyte[4] data;
string input = 8ab3060e2cba4f23b74cb52db3bdfb46;
auto p = input.ptr;
p++; p++;
data[0] = parse!ubyte((p-2)[0 .. 2], 16);
p++; p++;
data[1] = parse!ubyte((p-2)[0 .. 2], 16);
p++; p++;
data[2] = parse!ubyte((p-2)[0 .. 2], 16);
p++; p++;
data[3] = parse!ubyte((p-2)[0 .. 2], 16);
p++; p++;
return data;
}
enum ctfe = testCTFE();

void main()
{
import std.stdio;
writeln(testCTFE()); //[138, 179, 6, 14]
writeln(ctfe); //[138, 138, 138, 138]
}


Has this bug already been filed? I could possibly circumvent it by making
ragel use array indexing instead of pointers, but that'd be a performance
issue for runtime code as well.


Why would arrays be slower than pointers? You do know that you can turn
off array bounds checking?



Yes but the length has to be stored and updated, therefore for example 
p++ is less machine instructions/memory accesses/register pressure than 
arr = arr[1..$].





Re: writing iterators without code duplication. inout?

2011-12-21 Thread Timon Gehr

On 12/21/2011 04:54 PM, pompei2 wrote:

Hello.

I want to add the option to iterate objects of my class using foreach. I
need them to be iterable as view-only const and as mutable too. I would
prefer to iterate using the return a delegate but if that's not
possible, ranges are fine too. Also, I'd prefer a template-less solution
over a templated one.


This is what I have, which works but has severe code duplication. I
hoped inout would help me here, but I just can't figure it out. I also
gave a try to ranges, but same thing again: I can only get it to work if
I define my things twice.

(syntax highlight for the coming month: http://pastebin.com/TNmWWgsj)


import std.conv, std.stdio;

class Container
{
this(int from, int to)
{
while(from = to) {
_arr ~= from;
from++;
}
}

// FIXME: severe code duplication for const/nonconst/ref
// and I'm not even trying immutable yet
int delegate(int delegate(ref int)) doIter()
{
writeln(calling non-const);

int doTheIter(int delegate(ref int) dg)
{
int result = 0;
foreach(ref i ; this._arr) {
result = dg(i);
if(result)
break;
}
return result;
}

return doTheIter;
}

int delegate(int delegate(ref int)) doIter() const
{
writeln(calling const);

int doTheIter(int delegate(ref int) dg)
{
int result = 0;
foreach(i ; this._arr) {
result = dg(i);
if(result)
break;
}
return result;
}

return doTheIter;
}

int[] _arr;
}

int main(string[] args)
{
Container c = new Container(1, 9);
const Container cc = c;

foreach(ref e ; c.doIter()) {
writeln(e);
e++;
}

foreach(e ; cc.doIter()) {
writeln(e);
}

return 0;
}



Just remove the non-const overload. const member functions work with 
mutable, immutable and const receivers.


Re: How to mixin each element of tuple

2011-12-20 Thread Timon Gehr

On 12/20/2011 02:32 PM, Michal Minich wrote:

My naive approach doesn't works

struct Item1 (T) {}
struct Item2 (T) {}

struct Group (Items ...)
{
 // how to do this? ... no static foreach :(
 static foreach (I; Items)
 mixin I!(int);
}


void main ()
{
 alias Group!(Item1, Item2) G;
}


This will do what you want:

Solution 1:

struct Item1(T){}
struct Item2(T){}

mixin template getItems(Items ...){
static if(Items.length) {
private alias Items[0] _item;
mixin _item!int;
mixin getItems!(Items[1..$]);
}
}

struct Group(Items...)
{
mixin getItems!Items;
}

void main(){
alias Group!(Item1, Item2) G;
}


Solution 2:

struct Item1(T){}
struct Item2(T){}

struct Group(Items...) {
private static string gen(){
string r;
foreach(i;0..Items.length){
import std.conv;
r~=`private alias Items[`~text(i)~`] _item`~text(i)~`;`;
r~=`mixin _item`~text(i)~`!int;`;
}
return r;
}
mixin(gen());
}

void main(){
alias Group!(Item1, Item2) G;
}

But I'd rather have static foreach too.













Re: newbie question: Can D do this?

2011-12-20 Thread Timon Gehr

On 12/20/2011 03:18 PM, clk wrote:

Thank you for your quick replies. I'm impressed by the helpfulness and
dedication of the D community!
Here's another one. Is there a way to pass arguments to functions by
keyword as in the calls to f and g below?

void f(int a = 0, int b = 1) {}
void g(int a) {}

void main() {
f(b = 1, a = 0); // compile error
g(a = 0); // also compile error
}




No, there are no named arguments in D. Having them would sometimes be 
useful, but the drawback is that the parameter names become part of the 
public interface.






On 12/19/2011 03:00 PM, digitalmars-d-learn-requ...@puremagic.com wrote:

Send Digitalmars-d-learn mailing list submissions to
digitalmars-d-learn@puremagic.com

To subscribe or unsubscribe via the World Wide Web, visit
http://lists.puremagic.com/cgi-bin/mailman/listinfo/digitalmars-d-learn

or, via email, send a message with subject or body 'help' to
digitalmars-d-learn-requ...@puremagic.com

You can reach the person managing the list at
digitalmars-d-learn-ow...@puremagic.com

When replying, please edit your Subject line so it is more specific
than Re: Contents of Digitalmars-d-learn digest...


Today's Topics:

1. Re: newbie question: Can D do this? (Ali ?ehreli)
2. Re: newbie question: Can D do this? (Kai Meyer)
3. Re: newbie question: Can D do this? (Simen Kj?r?s)
4. Re: newbie question: Can D do this? (Ali ?ehreli)
5. Re: newbie question: Can D do this? (Jonathan M Davis)


--

Message: 1
Date: Mon, 19 Dec 2011 10:41:29 -0800
From: Ali ?ehreliacehr...@yahoo.com
To:digitalmars-d-learn@puremagic.com
Subject: Re: newbie question: Can D do this?
Message-ID:jco0gq$1ilt$1...@digitalmars.com
Content-Type: text/plain; charset=UTF-8; format=flowed

On 12/19/2011 08:17 AM, clk wrote:

I'm a little bit intimidated by the fact that the topics in the d-learn
list look rather advanced to a newbie like me.

We need more newbie topics here! :)

1) Does D support something like the javascript 1.8 destructuring
assigment (multiple assigment in python):
  
[a, b] = [b, a];

No multiple assignment like that. But useful approarches exist for most
needs, like the swap that simendsjo has shown.

2) D doesn't seem to support the list comprehension syntax available in
python and javascript. Is this correct?
  
[f(x) for x in list if condition]

List comprehension is not part of the language.

import std.algorithm;

void f(int x)
{}

bool condition(int x)
{
  return true;
}

void main()
{
  auto list = [ 0, 1, 2 ];
  map!f(filter!condition(list));
}

You can define f and condition within the body of main().

It is possible to use function literals as well:

import std.algorithm;

void main()
{
  auto list = [ 0, 1, 2 ];
  map!((x){
  /* ... this is f(x) ...*/
  })(filter!((x) {
  return true; /* ... condition ... */
  })(list));
}

3) D's slice operator apparently doesn't allow the use of a stride other
than unity as is allowed with fortran and matlab. Is there a way to
implement this feature so that
  
[1, 2, 3, 4, 5][0..$:2] would refer to [1, 3, 5], etc..., where 2 is the
non unit stride. Or is the find function from std.algorithm the only
option to achieve the same behavior.

std.range.stride does that:

import std.range;
// ...
stride([1, 2, 3, 4, 5], 2)

  
I find the 3 features above extremely convenient in every day coding.
Thanks,
-clk
  
  

Ali



--

Message: 2
Date: Mon, 19 Dec 2011 11:50:33 -0700
From: Kai Meyerk...@unixlords.com
To:digitalmars-d-learn@puremagic.com
Subject: Re: newbie question: Can D do this?
Message-ID:jco11q$1lle$1...@digitalmars.com
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

On 12/19/2011 09:17 AM, clk wrote:

Hello,
I'm new to this mailing list. I'm trying to learn D to eventually use it
in production code.
I'm a little bit intimidated by the fact that the topics in the d-learn
list look rather advanced to a newbie like me.
I have 3 fairly simple questions:

1) Does D support something like the javascript 1.8 destructuring
assigment (multiple assigment in python):

[a, b] = [b, a];

I would love multiple assignment like this, but it's tricky. But your
usage isn't really multiple assignment as much as it is a swap. What I'd
love is something like this:

[a, b, c] = [get_a(), get_b(), get_c()];

Or

[a, b, c] = [to!(int)(argv[1]), some_other_value, argv[4]);




2) D doesn't seem to support the list comprehension syntax available in
python and javascript. Is this correct?

[f(x) for x in list if condition]

No, D's syntax is very C-ish. I don't expect syntax like this to ever
show up (though what you are doing is possible with things like
std.algorithm)


3) D's slice operator apparently doesn't allow the use of a stride other
than unity as is 

Re: Void initialization

2011-12-20 Thread Timon Gehr

On 12/19/2011 01:04 PM, Bear wrote:

Using D1, I have a program that creates tons of float[] ; for performance
reasons, I would like them to be uninitialized.
I've tried replacing

float[] f = new float[x];
by
float[] f = cast(float[])std.gc.malloc(x*4);


Unfortunately I keep running into Access violation and sometimes Array
bounds error. I've tried adding

setTypeInfo(typeid(float), f.ptr);
and hasNoPointer(f.ptr);

which didn't work.

However
f[] = float.nan;
solved the problem, but kinda defeats the purpose of using malloc...
What am I doing wrong?


Are you using GDC?
https://bitbucket.org/goshawk/gdc/issue/287/casting-between-array-types-is-broken

If so, this is the workaround:

float[] f = (cast(float[])std.gc.malloc(x*4))[0..x];


Re: Void initialization

2011-12-20 Thread Timon Gehr

On 12/20/2011 07:12 PM, bearophile wrote:

Stewart Gordon:


On 19/12/2011 12:12, bearophile wrote:



Try something like this (untested):

alias float TF;
TF[] f = (cast(TF*)std.gc.malloc(x * TF.sizeof))[0 .. x];

snip

I fail to see any real difference from the OP's code:

- Why the alias?


Because in that code I have used three times a type (TF), auto allows to remove 
only one of them. The alias is not the best solution (a better solution is to 
put that code into a templated function), but repeating the same generic type 
more than one time is usually a source of bugs.



- std.gc.malloc returns the array with correct length according to my quick 
test, so the
use of [0..x] is redundant


Really? Well, as I have said I have not tested that code.
Generally GC functions return a void*, so to create an array I think you need 
to slice it... What is the code of your quick test?



- using TF.sizeof instead of 4 might fix things if on the user's platform float 
isn't 4
bytes long.


In D I think float is always 4 bytes long.



  Otherwise, while using .sizeof instead of a hard-coded number is better
practice, it isn't going to get rid of an AV.


I don't know what an AV is.

Bye,
bearophile


Access Violation.


Re: How to mixin each element of tuple

2011-12-20 Thread Timon Gehr

On 12/20/2011 07:13 PM, bearophile wrote:

Michal Minich:


struct Group (Items ...)
{
 // how to do this? ... no static foreach :(
 static foreach (I; Items)


In D if you use foreach on a typeTuple you get a static foreach.

Bye,
bearophile


Yes, but foreach cannot be used in declaration scope. I think having 
static foreach would greatly benefit the language. I regularly run into 
cases where I have to use one of the two inferior solutions when static 
foreach would be just the right tool for the job.


Re: delegate, template and alias

2011-12-19 Thread Timon Gehr

On 12/19/2011 06:46 PM, Philippe Sigaud wrote:

On Mon, Dec 19, 2011 at 15:35, Heromythbitwo...@qq.com  wrote:

Woo, I got it.


What's the difference with your first post?


He uses an eponymous template now.


Re: delegate, template and alias

2011-12-19 Thread Timon Gehr

On 12/19/2011 09:30 PM, Philippe Sigaud wrote:

On Mon, Dec 19, 2011 at 18:49, Timon Gehrtimon.g...@gmx.ch  wrote:

On 12/19/2011 06:46 PM, Philippe Sigaud wrote:


On Mon, Dec 19, 2011 at 15:35, Heromythbitwo...@qq.comwrote:


Woo, I got it.



What's the difference with your first post?



He uses an eponymous template now.


Ah yes, thanks. Strange, I'm pretty sure I used the eponymous trick
and it didn't work, for some reason.

Anyway, Heromyth, I'm slowly working on a D template tutorial. The
current pdf is at:

https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/dtemplates.pdf

(click on View Raw to download).

It's still incomplete. I'll work on it during the holidays and post on
D.announce to get some feedback on it, but you're welcome if you want
to give it a try.


Philippe


Looks very good.

Knowing it is a work in progress, I will already give some feedback:

You have a typo on page 15:
static if (is(T t = U[], U)) // is T an array of U, for some type U?

You probably meant to write

static if (is(T t == U[], U)) // is T an array of U, for some type U?

On page 18, I think your explanation why you used .power instead of 
power is not yet entirely accurate. The only reason why it is needed is 
because you are defining an eponymous template that hides the global 
template.


Also on page 18:

'Note that this template will work not only for unary (one argument) 
functions but also for n-args functions,'


The implementation given does not work for n-args functions because 
functions cannot return a tuple.


Page 23:

'Note that flatten works perfectly on ranges too, but is not lazy'

Ranges don't have the concatenation operator, so it will not work.

Page 25:

'And due to (to my eyes) a bug
in alias, you cannot alias them to a symbol:

alias (a){ return a;} Id; // Error'

It is a restriction that the current D grammar has. You can do this:

alias ID!((a){ return a;}) Id;

where ID is

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

Page 25:

'Since they are delegates, they can capture local symbols, as long as 
these are defined at compile-time:'


They can even capture local symbols that don't have a compile-time 
value. For example:


auto foo(alias s)(){return s();}

void main() {
int x = 2;
writeln(foo!({return x;})()); // prints '2'
}

And the link is purely symbolic, no closures or the like are allocated.

What the compiler effectively does is in the lines of this:

void main() {
int x = 2;
auto dgliteral() { return x; } // {return x;}
auto foo(){ return dgliteral(); } // foo!({return x})
writeln(foo()); // call template instance
}

This is one of the most powerful features of D templates: They are 
instantiated in the most local scope that is required for them to work.


Page 38:

'By the way, strangely enough, though you cannot declare ‘pure’ 
templates inside functions, you can declare struct templates.'


Do you want to file a bug report against this? This has bothered me a 
few times too.


Page 39:

Template this parameters are also useful to determine how the type of 
the this reference is qualified, (const/immutable/shared/inout)


Page 67:

'mixin template Concatenate()
{
Tuple!(This, U) opBinary(string op, this This)(This u)
if (op == ~)
{
return tuple(this, u);
}
Tuple!(U, This) opBinaryRight(string op, this This)(This u)
if (op == ~)
{
return tuple(u, this);
}
}'

I think what you meant was this:

mixin template Concatenate()
{
Tuple!(This, U) opBinary(string op, this This)(U u)
if (op == ~)
{
return tuple(this, u);
}
Tuple!(U, This) opBinaryRight(string op, this This)(U u)
if (op == ~)
{
return tuple(u, this);
}
}

Page 76:

'At the time of this writing,
the limitations are mostly: no classes and no exceptions (and so, no 
enforce).'


DMD 2.057 supports classes and exceptions in CTFE =)


Page 82:

I'd be careful with that table. Probably most of the ones you marked as 
'No' are actually 'Yes' when doing some clever things with is(typeof())?


Page 90:

'34 Extending a Class'

Maybe add a note that this does not work across module boundaries and 
therefore has not much practical use.


Page 90:

'return;
// or
return void;'

That looks like it was actual syntax.

Page 94/95:
'Strangely, you can only use it with the is(Type identifier, ...) 
syntax: you must have identifier.'


'For me, the main limitation is that template tuple parameters are not 
accepted. Too bad.'


Do you want to file the enhancement requests, or should I file them? 
Having those would increase the consistency of the language.




Keep up the good work!



Re: Array expanding

2011-12-18 Thread Timon Gehr

On 12/18/2011 11:12 PM, RenatoL wrote:

Reading the book from Alexandrescu we can find this (page 103-104,
at least in my edition):

Expanding arrays has a couple of subtleties that concern possible
reallocation of the array. Consider:

auto a = [87, 40, 10, 2];
auto b = a; // Now a and b refer to the same chunk
a ~= [5, 17]; // Append to a
a[0] = 15; // Modify a[0]
assert(b[0] == 15); // Pass or fail?

it seems natural that the test is ok but it is not... if we read
more we find:
D leaves~= the freedom of either expanding by reallocation or
opportunistically expanding in place if there is enough unused
memory at the end of the current array.

At a first glance this seems to be a serious issue... it seems hard
to accept that b can lost its connection to a in a silent mode due
to a reallocation

Is there a safe mode to do this for large arrays?



Assuming 'safe' means preserving aliasing: No. How would you implement 
it? Anyway, this is not such a huge issue in practice. If you want 
aliasing, just don't append to the slices.


Re: Array concat quiz

2011-12-17 Thread Timon Gehr

On 12/17/2011 02:43 AM, bearophile wrote:

A small quiz. This Python2 code:

m1 = [[A', B']]
print m1
m2 = m1 + [[]]
print m2


Prints:

[[A', B']]
[[A', B'], []]


What does this D2 program print?

import std.stdio;
void main() {
 string[][] m1 = [[A', B']];
 writeln(m1);
 string[][] m2 = m1 ~ [[]];
 writeln(m2);
}

Bye,
bearophile


I do not think that this is very sensible (array-array appends are more 
natural than array-element appends, so disambiguation should go the 
other way). Is it documented anywhere or is it just an implementation 
artefact?


Re: -D option = Embedded documentation

2011-12-16 Thread Timon Gehr

On 12/16/2011 06:12 PM, dune wrote:

What?

Sorry but I don't understand...

What I posted was an example, in reality there is tons of code inside the d 
file.

Thanks


That is not what you said. Obviously you should always give an example 
that actually fails, especially when you claim it does.


$ cat worksforme.d
/**
 * documentation here
 */
module worksforme;

/// program entry point
void main(){}

$ dmd -D worksforme
$ cat worksforme.html
htmlhead
META http-equiv=content-type content=text/html; charset=utf-8
titleworksforme/title
/headbody
h1worksforme/h1
!-- Generated by Ddoc from worksforme.d --
documentation herebrbr

dldtbigvoid umain/u();
/big/dt
ddprogram entry pointbrbr

/dd
/dl

hrsmallPage generated by a 
href=http://www.digitalmars.com/d/2.0/ddoc.html;Ddoc/a. /small

/body/html


Re: Restrict access to critical functions

2011-12-15 Thread Timon Gehr

On 12/15/2011 06:04 PM, Jonathan M Davis wrote:

On Thursday, December 15, 2011 13:57:21 deadalnix wrote:

Even haskell has non pure functions (IO monad for exemple).


Actually, Haskell is a 100% purely functional language.


Not entirely. For example: 
http://users.skynet.be/jyp/html/base/System-IO-Unsafe.html



Monads are completely
pure. They're _how_ Haskell manages to be pure with I/O, when every functional
language before them had had to be impure with regards to I/O.

- Jonathan M Davis




Re: Restrict access to critical functions

2011-12-14 Thread Timon Gehr

On 12/14/2011 01:28 PM, Kagamin wrote:

Goal would be to have a possibility to compile and let run code from
random people (some of them perhaps evil minded), watch over the
processes and kill them, if they take too long or use up too much memory.


I believe this is what SafeD is for.


SafeD eliminates the possibility of memory corruption, it does not 
prevent the program from messing with the system.


Re: Cartesian product of ranges?

2011-12-14 Thread Timon Gehr

On 12/14/2011 09:14 PM, Justin Whear wrote:

I've looked through std.algorithm and std.range, but haven't found anything
to compute the Cartesian product of several ranges. I have the nagging
feeling that this can be accomplished by combining several of the range
transformations in the standard library.

What I'm after is something like this:

alias Tuple!(int, string) P;
assert(equal(
cartesianProduct([1, 2], [a, b]),
[ P(1, a), P(1, b), P(2, a), P(2, b) ]
));



auto cartesianProduct(R,S)(R r, S s)if(isInputRange!R  isForwardRange!S){
struct CartesianProduct{
private{R r; S s, startS;}
this(R r, S s){this.r=r; this.s=s; startS=this.s.save;}
@property auto front(){return tuple(r.front, s.front);}
@property bool empty(){return r.empty;}
void popFront(){
s.popFront();
if(s.empty){
s = startS.save;
r.popFront();
}
}
static if(isForwardRange!R):
@property auto save(){return typeof(this)(r.save, s.save);}
}
return CartesianProduct(r,s);
}


Re: How is string from ... different from string from a file ?

2011-12-12 Thread Timon Gehr

On 12/12/2011 03:35 PM, ParticlePeter wrote:

Hi,

I have a hard time reading in a string from a file. I don't get any compile 
time or run time errors, but my application does not work reliably when I read 
a string from a file. But when I define the same string within my code, 
everything runs perfect, allways.
The string I want to use is an OpenGL Shader, but the problem is not to be 
related to OpenGL as far as a I see.
Are there some format strings which I need to get rid of, and how ?

I tried:
import std.file ;
string fragString = readText( Shader.vert ) ;

import std.file , std.utf ;
string fragString = toUTF8( readText( Shader.vert ) ) ;

import std.stdio ;
string text =  ;
auto file = File( Shader.vert ) ;
foreach( line ; file.byLine() )  string ~= strip( to!( string )( line ) ) ;

What else could I try ?

Cheers, ParticlePeter !



OpenGL probably wants a zero-terminated string. It works if you add the 
code as a literal because string literals are zero-terminated.


string fragString = readText( Shader.vert ) ~ '\0';

Alternatively, you can embed the file in you executable:

immutable string fragString = import( Shader.vert ); // read at 
compile time


Re: How is string from ... different from string from a file ?

2011-12-12 Thread Timon Gehr

On 12/12/2011 06:37 PM, bearophile wrote:

Timon Gehr:


string fragString = readText( Shader.vert ) ~ '\0';


I think using toStringz is more self-documenting.

Bye,
bearophile


There is nothing more self-documenting than actually appending the zero. 
Claiming toStringz is better in that regard is like saying a+1 is less 
self-documenting than doAddo(a) ;)
There might be other benefits of using toStringz though, (for example, 
it won't add the zero if it is already there, but that does not apply here).


Re: deep copy or shallow copy?

2011-12-09 Thread Timon Gehr

On 12/09/2011 09:32 PM, Ali Çehreli wrote:

On 12/08/2011 12:52 PM, Timon Gehr wrote:
  On 12/08/2011 09:50 PM, RenatoL wrote:
  snippet 1)
  auto arr1 = [1,2,3];
  auto arr2 = arr1;
  arr1[1] = 22;
  arr2[2] = 33;
  foreach (i; 0..arr1.length) write(arr1[i],  );
  writeln();
  foreach (i; 0..arr2.length) write(arr2[i],  );
 
  output:
  1 22 33
  1 22 33
  OK
 
  snippet 2)
 
  int[3] arr1 = [1,2,3];
  int[3] arr2 = arr1;
  arr1[1] = 22;
  arr2[2] = 33;
  foreach (i; 0..arr1.length) write(arr1[i],  );
  writeln();
  foreach (i; 0..arr2.length) write(arr2[i],  );
 
  output:
 
  1 22 3
  1 2 33
 
  that's unclear to me... i agree with the behaviour of the
  dynamic array... but if we have a static array we have a deep copy?
 
  Both copies are 'shallow', but static arrays are value types.

'shallow' would be misleading for a fixed-length (static) array because
there is nothing else but the elements for fixed-length arrays:


It is not misleading since the array might be an array of references. 
(and if it does not contain references, shallow and deep are the same 
thing anyway)




void main()
{
int[3] a;
assert(cast(void*)a == cast(void*)a[0]);
}

Fixed-length array storage is similar to C arrays. These are different:

- they don't decay to a 'pointer to first element' when passed to
functions (being value types, the whole array is copied)

- a.length is a convenience, equivalent to a.sizeof / a[0].sizeof

So it is impossible to do anything shallow with them unless we
explicitly maintain a pointer to a fixed-length array ourselves.

Ali



You can always slice it, of course

int[3] a;
int[] b = a[]; // b now is a dynamic array that aliases a's contents




Re: deep copy or shallow copy?

2011-12-08 Thread Timon Gehr

On 12/08/2011 09:50 PM, RenatoL wrote:

snippet 1)
auto arr1 = [1,2,3];
auto arr2 = arr1;
arr1[1] = 22;
arr2[2] = 33;
foreach (i; 0..arr1.length) write(arr1[i],  );
writeln();
foreach (i; 0..arr2.length) write(arr2[i],  );

output:
1 22 33
1 22 33
OK

snippet 2)

int[3] arr1 = [1,2,3];
int[3] arr2 = arr1;
arr1[1] = 22;
arr2[2] = 33;
foreach (i; 0..arr1.length) write(arr1[i],  );
writeln();
foreach (i; 0..arr2.length) write(arr2[i],  );

output:

1 22 3
1 2 33

that's unclear to me... i agree with the behaviour of the
dynamic array... but if we have a static array we have a deep copy?


Both copies are 'shallow', but static arrays are value types.


Re: C++ vs D aggregates

2011-12-04 Thread Timon Gehr

On 12/04/2011 12:00 PM, Kagamin wrote:

Dejan Lekic Wrote:


Do D2 aggregates behave the same, or are there notable differences?


D restricts usage to static initializers only, C++ doesn't have this limitation.


This works:

struct S{int x;}

void main(){
int a;
S x = {a};
}

What does not?


Re: Why is align() on structures not allowed within unit-test code blocks?

2011-12-04 Thread Timon Gehr

On 12/04/2011 03:01 PM, GrahamC wrote:

Is there a good reason why align() applied to structure definitions is not 
allowed on the struct definition line within unit-test code blocks?

E.g.:

unittest {

  align(1) struct Foo {
 char   c;
  int   i;
 }

  void Bar() {
Foo f;
  }

}

int main() {
  return 0;
}


fails to compile. The error message is:
 found 'align' instead of statement

The error message is the same for both DMD and GDC.

If you take the align(1) out it compiles OK.
If you move the structure definition out of the unit-test block but leave the 
align(1) in place it compiles OK.
If you put the align(1) on each member variable definition instead of the 
struct line it compiles OK.

If the structure type is only used within the unit-test code then I would think 
it ought to be possible to define it (including it's alignment attribute) 
within that unit-test code block.


The reason is that it is parsed as function-local and that DMD's parser 
for some strange reason uses different grammar rules for declarations 
when inside a function body. You could maybe file a bug report.


A possible workaround is to take the declaration out of the unittest 
block and wrap it into a version(unittest) block like this:



version(unittest) {
align(1) struct Foo {
char c;
int i;
}
}
unittest {
void Bar() {
Foo f;
}
}

int main() {
 return 0;
}

It invades the namespace of the module when compiling with -unittest though.


Re: Non-atomic ops allowed on shared variables?

2011-12-03 Thread Timon Gehr

On 12/03/2011 09:49 PM, Jonathan M Davis wrote:

On Saturday, December 03, 2011 21:41:45 Andrej Mitrovic wrote:

On 12/3/11, Jonathan M Davisjmdavisp...@gmx.com  wrote:

That page says that reads and writes are guaranteed to be atomic for
shared. It does _not_ say that something like ++threadsCount is
guaranteed to be atomic.


Woops, sorry it was a typo. I meant page 411, not 413. It says it's an
error there. Btw, I never said ++ was atomic, I've asked whether
something has changed. IOW I thought perhaps this used to be an error
but maybe it was changed to make increment/decrement to be atomic on
shared variables. That's not the case of course..


Ah, okay. I had completely forgotten about that. That seems _very_ restrictive
to me, and for it to work correctly, I would expect the compiler to have to be
smart enough to realize when a synchronized  block is in use or a mutex is in
use, and I don't see how it can be that smart across function calls (since if
it isn't that smart, it forces you to use atomicOp even when it's completely
unnecessary), so I don't see how that could possibly work without
unnecessarily requiring you to use atomicOp all over the place.

I have no idea what the plan on this is at this point, and I'm very surprised
that such a requirement was ever suggested. It's the kind of question that you
may have to bring up in the main newsgroup if you want a good answer for it
though, since the number of people who pay attention to d-learn is much lower,
and I don't know if any of the key devs who _would_ know pay attention here.

- Jonathan M Davis


cast()


Re: Non-atomic ops allowed on shared variables?

2011-12-03 Thread Timon Gehr

On 12/03/2011 11:30 PM, Jonathan M Davis wrote:

On Saturday, December 03, 2011 22:56:41 Timon Gehr wrote:

On 12/03/2011 09:49 PM, Jonathan M Davis wrote:

On Saturday, December 03, 2011 21:41:45 Andrej Mitrovic wrote:

On 12/3/11, Jonathan M Davisjmdavisp...@gmx.com   wrote:

That page says that reads and writes are guaranteed to be atomic for
shared. It does _not_ say that something like ++threadsCount is
guaranteed to be atomic.


Woops, sorry it was a typo. I meant page 411, not 413. It says it's an
error there. Btw, I never said ++ was atomic, I've asked whether
something has changed. IOW I thought perhaps this used to be an error
but maybe it was changed to make increment/decrement to be atomic on
shared variables. That's not the case of course..


Ah, okay. I had completely forgotten about that. That seems _very_
restrictive to me, and for it to work correctly, I would expect the
compiler to have to be smart enough to realize when a synchronized
block is in use or a mutex is in use, and I don't see how it can be
that smart across function calls (since if it isn't that smart, it
forces you to use atomicOp even when it's completely unnecessary), so I
don't see how that could possibly work without unnecessarily requiring
you to use atomicOp all over the place.

I have no idea what the plan on this is at this point, and I'm very
surprised that such a requirement was ever suggested. It's the kind of
question that you may have to bring up in the main newsgroup if you
want a good answer for it though, since the number of people who pay
attention to d-learn is much lower, and I don't know if any of the key
devs who _would_ know pay attention here.

- Jonathan M Davis


cast()


Sure, you could cast away shared, but there's something seriously wrong with
shared if you have to constantly cast it away in order to use a shared object.

- Jonathan M Davis


There is nothing wrong with shared. The type system is just not 
expressive enough to allow some perfectly fine code without casting to 
and away from shared now and then. Making it expressive enough would 
make the language more complex. And that system still would quite 
certainly be more conservative than necessary.





Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 05:05 PM, Adam wrote:

To step back a bit, what is the *benefit* of not requiring a class
to be declared abstract if it does not override an abstract member?
It introduces implicit behavior and the potential for an additional
test case (in *what* sane world should I even HAVE to test that
something is instantiable?) for the sake of not typing 8 characters
in a Class definition


A second possible use case:

class C(T): T{
// some declarations
}

Now you really want that template to be instantiable with T being either 
an abstract or a concrete class. Anything else is bound to become 
extremely annoying.


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 08:10 PM, Adam wrote:



A second possible use case:

class C(T): T{
  // some declarations
}



Now you really want that template to be instantiable with T being

either

an abstract or a concrete class. Anything else is bound to become
extremely annoying.


Could you expand on this case a bit? I'm not sure I follow the point
one way or another.


This is an useful pattern. I don't have a very useful example at hand, 
but this one should do. It does similar things that can be achieved with 
traits in Scala for example.



import std.stdio;
abstract class Cell(T){
abstract void set(T value);
abstract const(T) get();
private:
T field;
}

class AddSetter(C: Cell!T,T): C{
override void set(T value){field = value;}
}
class AddGetter(C: Cell!T,T): C{
override const(T) get(){return field;}
}

class DoubleCell(C: Cell!T,T): C{
override void set(T value){super.set(2*value);}
}

class OneUpCell(C: Cell!T,T): C{
override void set(T value){super.set(value+1);} 
}

class SetterLogger(C:Cell!T,T): C{
override void set(T value){
super.set(value);
writeln(cell has been set to ',value,'!);
}
}

class GetterLogger(C:Cell!T,T): C{
override const(T) get(){
auto value = super.get();
writeln(',value,' has been retrieved!);
return value;
}
}

class ConcreteCell(T): AddGetter!(AddSetter!(Cell!T)){}
class OneUpDoubleSetter(T): OneUpCell!(DoubleCell!(AddSetter!(Cell!T))){}
class DoubleOneUpSetter(T): DoubleCell!(OneUpCell!(AddSetter!(Cell!T))){}
void main(){
Cell!string x;
x = new ConcreteCell!string;
x.set(hello);
writeln(x.get());

Cell!int y;
y = new SetterLogger!(ConcreteCell!int);
y.set(123); // prints: cell has been set to '123'!

y = new GetterLogger!(DoubleCell!(ConcreteCell!int));
y.set(1234);
y.get(); // prints '2468' has been retrieved!

y = new AddGetter!(OneUpDoubleSetter!int);
y.set(100);
writeln(y.get()); // prints 202

y = new AddGetter!(DoubleOneUpSetter!int);
y.set(100);
writeln(y.get()); // prints 201

// ...
}


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 09:05 PM, Timon Gehr wrote:

On 12/02/2011 08:10 PM, Adam wrote:



A second possible use case:

class C(T): T{
// some declarations
}



Now you really want that template to be instantiable with T being

either

an abstract or a concrete class. Anything else is bound to become
extremely annoying.


Could you expand on this case a bit? I'm not sure I follow the point
one way or another.


This is an useful pattern. I don't have a very useful example at hand,
but this one should do. It does similar things that can be achieved with
traits in Scala for example.


import std.stdio;
abstract class Cell(T){
abstract void set(T value);
abstract const(T) get();
private:
T field;
}

class AddSetter(C: Cell!T,T): C{
override void set(T value){field = value;}
}
class AddGetter(C: Cell!T,T): C{
override const(T) get(){return field;}
}

class DoubleCell(C: Cell!T,T): C{
override void set(T value){super.set(2*value);}
}

class OneUpCell(C: Cell!T,T): C{
override void set(T value){super.set(value+1);}
}

class SetterLogger(C:Cell!T,T): C{
override void set(T value){
super.set(value);
writeln(cell has been set to ',value,'!);
}
}

class GetterLogger(C:Cell!T,T): C{
override const(T) get(){
auto value = super.get();
writeln(',value,' has been retrieved!);
return value;
}
}

class ConcreteCell(T): AddGetter!(AddSetter!(Cell!T)){}
class OneUpDoubleSetter(T): OneUpCell!(DoubleCell!(AddSetter!(Cell!T))){}
class DoubleOneUpSetter(T): DoubleCell!(OneUpCell!(AddSetter!(Cell!T))){}
void main(){
Cell!string x;
x = new ConcreteCell!string;
x.set(hello);
writeln(x.get());

Cell!int y;
y = new SetterLogger!(ConcreteCell!int);
y.set(123); // prints: cell has been set to '123'!

y = new GetterLogger!(DoubleCell!(ConcreteCell!int));
y.set(1234);
y.get(); // prints '2468' has been retrieved!

y = new AddGetter!(OneUpDoubleSetter!int);
y.set(100);
writeln(y.get()); // prints 202

y = new AddGetter!(DoubleOneUpSetter!int);
y.set(100);
writeln(y.get()); // prints 201

// ...
}


Oh, forgot to mention: This would not compile, if an explicit 'abstract' 
declaration on template class definitions was required.


Re: Abstract functions in child classes

2011-12-02 Thread Timon Gehr

On 12/02/2011 09:27 PM, Adam wrote:

So this pattern allows you to provide partial implementations of an
abstract, and use template specialization to provide a sort of
multiple inheritance rather than strict class definition /
extension. That's important in Scala because of the lack of multiple
inheritance (as I understand it).

Am I understanding this correctly - that the point of this approach is
to replicate composition by multiple inheritance?


You can do that, but templates provide you with a lot more power. Note 
that some of my examples cannot be expressed as nicely in terms of 
multiple inheritance. That is because they rely on the order in which 
the classes are composed. This is sometimes discouraged in Scala afaik. 
I think, because there the type of an object does not depend on the 
trait mixin order. (not an issue here)


Parameterizing on the base class has quite some applications, its 
applications in C++ even have an own wikipedia page:


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


Re: Profile DMD

2011-12-01 Thread Timon Gehr

On 12/01/2011 07:42 PM, Nick Sabalausky wrote:

Is there an easy way to profile DMD similar to how DMD itself has
the -profile switch?




Use DMC, I guess. http://www.digitalmars.com/ctg/trace.html


Re: idea for variant improvement

2011-11-30 Thread Timon Gehr

On 11/30/2011 07:53 PM, bioinfornatics wrote:

Variant is very usefull but a function who take a variant as parameter
do not works whithout a cast. but You can assign a value form any type
in statement Variant v = 2u.
the code below explain well the problem
---
import std.string;
import std.stdio;
import std.variant;

void func( Variant param ){
 writeln( it works );
}

void func2( T )( T param ){
 Variant a = cast(Variant) param;
 writeln( it works );
}

void main( string[] args ){
 Variant a = 2u; // works
 func( a );
 //func( 2u ); // does not works
 func2( 2u );
}
--

It will be great if function func work in all case



Vote here: http://d.puremagic.com/issues/show_bug.cgi?id=7019


Re: idea for variant improvement

2011-11-30 Thread Timon Gehr

On 11/30/2011 11:55 PM, bioinfornatics wrote:

Le mercredi 30 novembre 2011 à 22:19 +0100, Timon Gehr a écrit :

On 11/30/2011 07:53 PM, bioinfornatics wrote:

Variant is very usefull but a function who take a variant as parameter
do not works whithout a cast. but You can assign a value form any type
in statement Variant v = 2u.
the code below explain well the problem
---
import std.string;
import std.stdio;
import std.variant;

void func( Variant param ){
  writeln( it works );
}

void func2( T )( T param ){
  Variant a = cast(Variant) param;
  writeln( it works );
}

void main( string[] args ){
  Variant a = 2u; // works
  func( a );
  //func( 2u ); // does not works
  func2( 2u );
}
--

It will be great if function func work in all case



Vote here: http://d.puremagic.com/issues/show_bug.cgi?id=7019


yes thanks i will do. And you you do not vote for this feature?



I already have =).
http://d.puremagic.com/issues/votes.cgi?action=show_bugbug_id=7019


Re: Make a variable single-assignment?

2011-11-30 Thread Timon Gehr

On 12/01/2011 12:08 AM, Stewart Gordon wrote:

On 21/11/2011 20:06, Jesse Phillips wrote:

What you are describing is Head Const, and is not available.

http://www.d-programming-language.org/const-faq.html#head-const

It will not be added as it doesn't provide any guarantees about the
code that is useful
to the compiler.  It can't be added to the existing system without
complicating the type
system even more, which outweighs the benefits.

snip

Guarantees about the code don't need to be useful to the compiler - they
can be just useful to the programmer. After all, this is the main point
of DbC.

And it doesn't need to be a full-fledged head const. At the simplest, a
single-assignment variable could just be an rvalue - something of which
the address cannot be taken and so the absence of head const becomes
irrelevant.

That said, it isn't much complexity to allow the address to be taken of
such a thing

final T data;
auto ptr = data;

with the following rules:
- if T is a value type, immutable(something)[] or immutable(something)*,
then data is an immutable(T)*
- otherwise, data is a const(T)*.

Once upon a time there was const/final/invariant. What exactly did final
do back then?

Stewart.


Here is some documentation from that time:
http://www.digitalmars.com/d/final-const-invariant.html

It did indeed mean head const, like in Java. I wonder why it was removed 
from the design though, it gives extra expressiveness at no cost. (maybe 
because then people will start pushing for readonly (tail const)? :))


Re: Overhead of synchronized class used in unshared situation

2011-11-28 Thread Timon Gehr

On 11/28/2011 07:37 AM, breezes wrote:

Thanks. It seems that I have to write two classes, one synchronized and one is 
not. Of course the
synchronized one should be the wrapper.

However, all members of a synchronized class are also shared. So I can not use 
the un-synchronized class
in the synchronized wrapper class directly. I found two ways to overcome this 
problem:
1. Cast away shared whenever using the wrapped un-synchronized object.
2. Define the wrapped un-synchronized object as __gshared.

Which way if more preferred?


The first one.

You manually ensure, by locking, that the object is actually unshared 
during that particular time frame and that there are memory fences. 
Casting away shared makes that information available to the compiler.


Re: Make a variable single-assignment?

2011-11-21 Thread Timon Gehr

On 11/21/2011 03:04 PM, Alex Rønne Petersen wrote:

Hi,

Is there any way to make a variable single-assignment, regardless of its
type? I.e.:

void foo()
{
some magical keyword? int i = 0;
i = 2; // Error: i cannot be reassigned
}

I realize const and immutable will do this, but they are transitive and
infect the type, which I do *not* want. I simply want the variable to be
single-assignment. Is it possible?

- Alex


How should that be possible without infecting the type?

void main(){
magical keyword int i = 0;
auto a = i;
*a = 2; // oops...
}


Re: Mutable enums

2011-11-17 Thread Timon Gehr

On 11/17/2011 03:19 PM, Steven Schveighoffer wrote:

On Wed, 16 Nov 2011 17:39:16 -0500, Timon Gehr timon.g...@gmx.ch wrote:


On 11/16/2011 10:56 PM, Steven Schveighoffer wrote:

On Wed, 16 Nov 2011 16:16:48 -0500, Timon Gehr timon.g...@gmx.ch
wrote:


On 11/16/2011 09:00 PM, Steven Schveighoffer wrote:

On Wed, 16 Nov 2011 14:26:57 -0500, Timon Gehr timon.g...@gmx.ch
wrote:


On 11/16/2011 02:22 PM, Steven Schveighoffer wrote:

On Tue, 15 Nov 2011 13:45:02 -0500, Timon Gehr timon.g...@gmx.ch
wrote:


Note that this is an explicit allocation:

int[] a = [1,2,3]; // just as explicit as a NewExpression

Only the enums hide it sometimes, but actually you should know
the
involved types.


As I've said, there are already ways to explicitly allocate
memory. A
suggested replacement for this is:

int[] a = array(1, 2, 3);

And you could always do:

int[] a = [1, 2, 3].dup;

Nobody complains about having to do:

char[] a = hello.dup;

I don't see why we couldn't do the same for all array literals.



Because 'immutable' behaves nicely on built-in value types, but
not on
arbitrary reference types.


string is a reference type. We hear no complaints about strings being
stored in ROM and the type of literals being immutable.



string is not an immutable type. It is immutable(char)[] and char is a
built-in value type.

static assert(isMutable!string);


It fits my definition of a valid enum reference type (immutable or
implicitly castable to immutable). The point is that the data referenced
is stored in ROM and therefore a) immutable and b) fully defined at
compile-time.


Indeed. But fact is, the data that is qualified with immutable is not
of reference type therefore it behaves nicely. And you don't get that
in the general case.


In the general case, there is always a library function for
construction. In other words, what the compiler currently does for array
literals can be done in a library. But a library cannot create ROM
space. The compiler-based features (and CTFE in general) should be
helping us create things at compile time, not at run time. We already
have the tools to construct arrays at runtime.



I am looking for something like this:

template writeln(T...)(T){
alias writelnImpl!(writelnInferConst!T) writeln;
}

(it is even trivial to parse, unlike normal function definitions!)


What does writelnInferConst!T do? I'm afraid I'm not getting what you
are saying.

I was thinking writeln should do this:

void writeln(T...)(const T args) {...}


As you pointed out, this cannot print types that have a non-const 
toString method (caching the result could be a perfectly valid reason 
for that.)


writelnInferConst finds out which parameters can be treated as const and 
still be printed so that the correct version of writeln may be called.


For example:

class Foo{ // can be printed if const
string toString()const{return Foo;}
}

class Bar{ // cannot be printed if const
string cache;
string toString(){return cache!is null?cache:(cache=Bar);}
}

template hasConstToString(T){
enum hasConstToString = is(typeof((const T t){return t.toString();}));
}

template writelnInferConstImpl(T...){
static if(!T.length) alias T X;
else static if(hasConstToString!(T[0])){
alias T[0] _;
alias TypeTuple!(const(_),writelnInferConst!(T[1..$])) X;
}else
alias TypeTuple!(T[0],writelnInferConst!(T[1..$])) X;
}
template writelnInferConst(T...){alias writelnInferConstImpl!T.X 
writelnInferConst;} // (bug 6966)



static 
assert(is(writelnInferConst!(Foo,Bar,Foo,Foo,Bar)==TypeTuple!(const(Foo),Bar,const(Foo),const(Foo),Bar)));



The real thing would also do stuff like

actual argument immutable(Foo[])[] = formal argument const(Foo[][]).

In order to get rid of bloat created by pointless instantiations of 
writelnImpl.







I have an enhancement request in for intercepting IFTI (not sure if it
applies here): http://d.puremagic.com/issues/show_bug.cgi?id=4998



It has a complexity of at least 2^numparams and probably all kinds of
odd implications for the compiler internals that would lead to a buggy
implementation.


I'm not a compiler writer, but I don't see how this is the case.


There were/are quite a few error gagging related bugs. I guess this 
would be similar.






I think this is a better solution:

void foo2(T: ParameterTypeTuple!foo[0])(T t){foo(t);}

Then it is just a matter of applying proper value range propagation
for IFTY:

void bar(T: short)(T t){...}

void main(){
bar(1); // ok
}


The issue with all this is, IFTI doesn't work that way:

void foo(T: short)(T t) {}

void main()
{
foo(1);
}

testifti.d(5): Error: template testifti.foo(T : short) does not match
any function template declaration
testifti.d(5): Error: template testifti.foo(T : short) cannot deduce
template function from argument types !()(int)

IFTI decides the types of literals before trying to find a proper
template to instantiate. Any possibility to intercept the decision of
literal type

Re: Using __traits(getMember...) in alias statement

2011-11-17 Thread Timon Gehr

On 11/17/2011 06:12 PM, Tobias Pankrath wrote:

It would be cool, if the following would be possible.

immutable string MemberID = M;

struct A {}
struct B {
 alias A M;
}

template Member(T)
{
 static if(__traits(hasMember, T, MemberID))
 {
 alias __traits(getMember, T, MemberID) Member;
 }
 else
 alias TypeTuple!() Member;
}

void main()
{
 alias Member!(B) M;
}


Currently dmd will print basic type expected, not __traits.
Why isn't traits allowed here and if we allow __traits there, would this
introduce any ambiguities?



This works:

alias TypeTuple!(__traits(getMember, T, MemberID)) Member;

It is a mere grammar issue. The aliased symbol must look like a valid 
type. I'd like that to change too.


This helps a lot with the current state of affairs:

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


It will even allow funny things like this:

alias ID!((a,b){return a+b;}) add;

static assert(add(1,2) == 3);


Re: Using __traits(getMember...) in alias statement

2011-11-17 Thread Timon Gehr

On 11/17/2011 06:41 PM, Timon Gehr wrote:

On 11/17/2011 06:12 PM, Tobias Pankrath wrote:

It would be cool, if the following would be possible.

immutable string MemberID = M;

struct A {}
struct B {
alias A M;
}

template Member(T)
{
static if(__traits(hasMember, T, MemberID))
{
alias __traits(getMember, T, MemberID) Member;
}
else
alias TypeTuple!() Member;
}

void main()
{
alias Member!(B) M;
}


Currently dmd will print basic type expected, not __traits.
Why isn't traits allowed here and if we allow __traits there, would this
introduce any ambiguities?



This works:

alias TypeTuple!(__traits(getMember, T, MemberID)) Member;


This only works if the __traits gets you a TypeTuple back. (It won't 
work in this case, it will create a one-element tuple). Better use ID 
from below.





It is a mere grammar issue. The aliased symbol must look like a valid
type. I'd like that to change too.

This helps a lot with the current state of affairs:

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


It will even allow funny things like this:

alias ID!((a,b){return a+b;}) add;

static assert(add(1,2) == 3);




Re: Mutable enums

2011-11-17 Thread Timon Gehr

On 11/17/2011 07:23 PM, Steven Schveighoffer wrote:

On Thu, 17 Nov 2011 12:31:58 -0500, Timon Gehr timon.g...@gmx.ch wrote:


On 11/17/2011 03:19 PM, Steven Schveighoffer wrote:




What does writelnInferConst!T do? I'm afraid I'm not getting what you
are saying.

I was thinking writeln should do this:

void writeln(T...)(const T args) {...}


As you pointed out, this cannot print types that have a non-const
toString method (caching the result could be a perfectly valid reason
for that.)


Caching string representation IMO is not a significant use case. Not
only that, but toString should be deprecated anyways in favor of a
stream-based system.


writelnInferConst finds out which parameters can be treated as const
and still be printed so that the correct version of writeln may be
called.

For example:

class Foo{ // can be printed if const
string toString()const{return Foo;}
}

class Bar{ // cannot be printed if const
string cache;
string toString(){return cache!is null?cache:(cache=Bar);}
}

template hasConstToString(T){
enum hasConstToString = is(typeof((const T t){return t.toString();}));
}

template writelnInferConstImpl(T...){
static if(!T.length) alias T X;
else static if(hasConstToString!(T[0])){
alias T[0] _;
alias TypeTuple!(const(_),writelnInferConst!(T[1..$])) X;
}else
alias TypeTuple!(T[0],writelnInferConst!(T[1..$])) X;
}
template writelnInferConst(T...){alias writelnInferConstImpl!T.X
writelnInferConst;} // (bug 6966)


static
assert(is(writelnInferConst!(Foo,Bar,Foo,Foo,Bar)==TypeTuple!(const(Foo),Bar,const(Foo),const(Foo),Bar)));



If your goal is to reduce template bloat, I think this is not the solution.

But also note that this still does not guarantee const. I don't really
see the point of doing all these templates if you aren't going to
guarantee writeln doesn't modify the data.



The issue with all this is, IFTI doesn't work that way:

void foo(T: short)(T t) {}

void main()
{
foo(1);
}

testifti.d(5): Error: template testifti.foo(T : short) does not match
any function template declaration
testifti.d(5): Error: template testifti.foo(T : short) cannot deduce
template function from argument types !()(int)

IFTI decides the types of literals before trying to find a proper
template to instantiate. Any possibility to intercept the decision of
literal type or of instantiation would be useful. I think that it's
better suited to the constraints, because there is more power there. But
I'm not sure. If you can find a more straightforward way, I'm all for
it.

In any case, I need to update the bug report, because the general case
is if foo has an overload. For instance:

foo(short s);
foo(wstring w);

foo2 should be able to call both with 1 and hello without issue.

My driving use case to create the enhancement was creating a wrapper
type that intercepted function calls. I planned to use opDispatch, but
it didn't quite work with literals.


Ok, I see the problem. My proposed IFTI template mechanism would save
the day.

It would look like this (static foreach would have to be replaced by a
recursive mixin template because Walter encountered implementation
difficulties).


template OverloadsOf(alias symbol){ // should this be in std.traits?
alias TypeTuple!(__traits(getOverloads, __traits(parent,symbol),
__traits(identifier,symbol))) OverloadsOf;
}

auto wrapper(alias foo)(ParameterTypeTuple!foo args){
return foo(args);
}
template opDispatch(string op,T...)(T){
static foreach(foo; OverloadsOf!(mixin(op))){
alias wrapper!foo opDispatch;
}
static if(OverloadsOf!(mixin(op)).length==0) { // we are dealing with
a template function
auto opDispatch(T args){
return foo(args);
}
}
}


Pardon my saying so, but this looks horrendous. Not to mention that I
don't think it would work.


Oh, it would certainly work.


IFTI instantiates templates, it does not look
inside instantiated templates for overloads.


This works, does this solve the confusion?:

void foo(int){writeln(foo!);}
void bar(double){writeln(bar!);}

template merge(){
alias foo qux;
alias bar qux;
}
alias merge!().qux qux;

void main(){
qux(1);   // calls foo
qux(1.0); // calls bar
}





BTW, your proposed IFTI template mechanism, do you have it stated
anywhere? Maybe it fixes the problem I mentioned.


Not yet, I will file a bugzilla enhancement request and post a link here.

What it does is quite simple:

1. Apply normal IFTI instantiation rules to the IFTI template, as if it 
was a function template.

2. Instantiate the IFTI template with the deduced arguments.
3. The result of the instantiation must be callable with the original 
arguments. Call it.


This allows the function that is called to have a different (albeit 
compatible) signature from what IFTI would give you.






Seems rather odd you should have to jump through these hoops to get the
compiler to use ROM space. But I concede that I did not know of this
trick. It does not sway my opinion that CTFE should produce ROM-stored
references, and library function

Re: Mutable enums

2011-11-16 Thread Timon Gehr

On 11/16/2011 02:22 PM, Steven Schveighoffer wrote:

On Tue, 15 Nov 2011 13:45:02 -0500, Timon Gehr timon.g...@gmx.ch wrote:


On 11/15/2011 04:53 PM, Steven Schveighoffer wrote:



Yes, but this is spelled out because copying a static array requires
moving data. However, this does *not* require a hidden allocation (even
though it does do a hidden allocation currently).

I'm not worried about copying data as much as I am about hidden
allocations. Hidden allocations are a huge drag on performance. Every
time you allocate, you need to take a global GC lock, and it's an
unbounded operation (doing one allocation could run a collection cycle).


You don't actually _need_ a global GC lock. It is just how it is
implemented in this case.


This is all fine in theory. I haven't seen any implementations. But
memory allocations are not cheap, even without a GC lock.


Note that this is an explicit allocation:

int[] a = [1,2,3]; // just as explicit as a NewExpression

Only the enums hide it sometimes, but actually you should know the
involved types.


As I've said, there are already ways to explicitly allocate memory. A
suggested replacement for this is:

int[] a = array(1, 2, 3);

And you could always do:

int[] a = [1, 2, 3].dup;

Nobody complains about having to do:

char[] a = hello.dup;

I don't see why we couldn't do the same for all array literals.



Because 'immutable' behaves nicely on built-in value types, but not on 
arbitrary reference types.




That is the idea. Get rid of the hidden allocation. Writeln *is* const
correct, it can certainly print immutable(int)[].


Well, there is a function called writeln that can do that. That is a
different function. But the one that gets actually called is not const
correct as well.


This is writeln:

// Most general instance
void writeln(T...)(T args)
if (T.length  1 || T.length == 1  !is(typeof(args[0]) :
const(char)[]))
{
stdout.write(args, '\n');
}


=
writeln([1,2,3]);
// modulo IFTY:
writeln!(int[])([1,2,3]);
// const correct?
writeln!(int[])([1,2,3].idup); // nope!

Error: cannot implicitly convert expression (_adDupT(
_D11TypeInfo_Ai6__initZ,[1,2,3])) of type immutable(int)[] to int[]


I'm not sure what this means. If [1, 2, 3] is typed as immtuable(int)[],
it will compile.

Simple test:

immutable(int)[] a = [1, 2, 3];
writeln(a);

works with 2.056.


That is like saying

void foo(int[] a){...} // prints a
void bar(immutable(int)[] a){...}  // prints a

int[] a = [1,2,3];
immutable(int)[] b = [1, 2, 3];
foo(a);
bar(b);

= Oh, bar is const correct because I can call foo with mutable data 
and bar with immutable data.


foo is writeln!(int[])
bar is writeln!(immutable(int)[])

in effect, if you do:

writeln(hello.dup);

The compiler cannot assume that the IFTI'd writeln!(char[]) will not 
change the argument, ergo it cannot optimize away the .dup, even though 
it would be a valid transformation as long as the programmer does not 
make the program semantics depend on the identity relation on immutable 
references (doing so defeats the purpose of immutability).






The issue is not
writeln, it's what the type of the array literal/enum is.




Technically, an array literal is equivalent to an enum, and should
follow the same rules.



Remember that immutable is transitive. That can really get in your way
in this case.


If the data is stored in ROM, it should be typed as immutable. If it's
not, then it could be modified. The only other option is heap allocation
and construction on use, which I've already said is undesirable.

If we start from all array literals and enums that contain references
store the referenced data in ROM, then we will find ways to deal with
any inconveniences. It's all a matter of what's more important in a
system language, performance or convenience.


Both are more important. It is D.
Everything you need to do is make the enum static immutable instead.
D is also a scripting language and an application programming language.

auto a = [new Foo, new Bar, new Qux]; // I want that to work.








Re: Mutable enums

2011-11-16 Thread Timon Gehr

On 11/16/2011 08:26 PM, Timon Gehr wrote:

auto a = [new Foo, new Bar, new Qux]; // I want that to work.



(It currently does, if that was unclear)



<    2   3   4   5   6   7   8   9   >