Re: "static" means too many things

2012-05-02 Thread Timon Gehr

On 05/02/2012 01:46 AM, bearophile wrote:

This is the brief of some D code, it shows one consequence of the
excessive overloading of the D "static" keyword:

struct Foo {
bool solve() {
/*static*/ bool fill(int r, int c, Cell n) {
// ...
if (fill(r + i, c + j, n + 1))
return true;
}

return fill(x, y, 1);
}
}

The Foo struct has solve() instance method, solve() contains and
calls a nested (recursive) function named fill().

fill() has to use instance attributes, so it can't be a static
struct function regarding the struct Foo. On the other hand the
nested function fill() doesn't need variables defined inside the
method solve(), so it doesn't require a frame pointer to solve(),
so it's static for solve().

The problem is that "static" is used to denote both nested
functions that have no frame pointer (they are often faster and
they tend to be less buggy because they can't use names from
outer scopes, almost like pure functions), and static struct
methods :-)

So to denote a function that doesn't need a frame pointer
something like "@noframe" sounds better than "static".

In practice this is not a very common situation, and fill() here
is not performance-critical, so keeping the frame pointer is not
so bad (I also annotate fill() with "pure", so despite not being
static to solve() it's able to use only immutable names from the
scope of solve()).

Where performance is very important it suffices to pull fill()
out of solve(), define it as a private instance method, and maybe
rename it to _fill() or something similar.

Bye,
bearophile


 'fill' should accept the 'this' pointer instead of the frame pointer, 
without programmer interaction. This is a local optimisation. If you 
need to guarantee that the double pointer dereference does not occur, 
make 'fill' a private instance method. I don't see the need of 
introducing additional syntax here.




std.stdio File doesn't support Win UTF16 file systems?

2012-05-02 Thread Oleg Kuporosov
Hi all,

Looking into the source (it uses DM's libc) did I get right that
std.stdio.File can't work with UTF16 names in Windows?
I've tried to find bug# but failed too. There is  Issue#7648 "Can't open
file (Windows UTF8)" only but UTF8 is not native for
Windows filesystems anyway. Is there any plans to have std.stdio based on
std.stream with UTF16 support for filesystems?

Thaks,
Oleg.


Re: is there a difference between those two notations

2012-05-02 Thread Christian Köstlin

On 04/30/2012 11:03 PM, bearophile wrote:

Christian Köstlin:


reduce!((int a, int b){return a+b;})(iota(100))
reduce!("a+b")(iota(100))


Today the syntaxes I prefer are:

iota(100).reduce!q{a + b}()

iota(100).reduce!((a, b) => a + b)()

But hopefully in some we'll have an efficient sum() function too in Phobos:

iota(100).sum()

Bye,
bearophile

thanks for this tip.
i always forget about this nice d feature :)

regards

christian



Access Violation in callback from sort

2012-05-02 Thread Jabb
Just got the TDPL book and it's a great read! I learn best when 
typing out the code myself, so I decided to make a single VisualD 
project and put the different exercises in separate modules. I am 
having problems with sort in std.algorithms - well, actually it 
appears to be a closure problem when sort calls my delegate.


Here's a sample of the problem - in main.d I have

//--
module main;
import std.algorithm;
void main() {
uint[string] counts = [ "a":4, "b":5, "c":3, "d":1 ];
string[] keys = counts.keys;

sort!((a, b) { return counts[a] > counts[b]; })(keys);
}
//--

Alone this works just fine. But if I add another file called 
myalgs.d, and put the following in it:


//--
module myalgs;
import std.algorithm;
//--

Then I get the following exception:

object.Error: Access Violation

C:\D\dmd2\windows\bin\..\..\src\phobos\std\algorithm.d(7112): 
mainmain__T8sortImplS14main9__lambda3VE3std9algorithm12SwapStrategy0TAAyaZsortImpl



Steping through the code it appears that the Access Violation 
occurs when accessing counts[a].


I am using DMD32 v2.059; my compilation command line looks like:
dmd -g -debug -X -Xf"$(IntDir)\$(TargetName).json" 
-deps="$(OutDir)\$(ProjectName).dep" 
-of"$(OutDir)\$(ProjectName).exe_cv" -map 
"$(INTDIR)\$(SAFEPROJECTNAME).map" -L/NOMAP


Am I doing something wrong here?

thanks for the help!


ref semantics with hashes

2012-05-02 Thread Andrej Mitrovic
import std.stdio;

struct Foo
{
int[int] hash;
}

void main()
{
test1();
test2();
}

void test1()
{
Foo foo;
foo.hash[1] = 1;

auto hash2 = foo.hash;
hash2[2] = 2;
writeln(foo.hash);  // [1:1, 2:2]
writeln(hash2); // [1:1, 2:2]
}

void test2()
{
Foo foo;
auto hash2 = foo.hash;
hash2[2] = 2;
writeln(foo.hash);  // [] ??
writeln(hash2); // [2:2]
}

So if the hash wasn't already initialized then the reference in the
Foo struct is a reference to null, and if you duplicate that reference
and add a key the old reference still points to null.

The only way to ensure a proper link with a hash is to initialize it
with a key and then immediately remove that key, which makes the hash
not-null but empty:

import std.stdio;

class Foo
{
int[int] hash;
this() { hash[0] = 0; hash.remove(0); }  // make it not null but empty
}

void main()
{
test1();
test2();
}

void test1()
{
Foo foo = new Foo;
foo.hash[1] = 1;

auto hash2 = foo.hash;
hash2[2] = 2;
writeln(foo.hash);  // [1:1, 2:2]
writeln(hash2); // [1:1, 2:2]
}

void test2()
{
Foo foo = new Foo;
auto hash2 = foo.hash;
hash2[2] = 2;
writeln(foo.hash);  // [2:2]
writeln(hash2); // [2:2]
}

Why do we have such error-prone semantics?


Re: Passing array as const slows down code?

2012-05-02 Thread Joseph Rushton Wakeling

On 30/04/12 16:03, Steven Schveighoffer wrote:

Try removing the ref and see if it goes back. That usage of ref should not
affect anything (if anything it should be slower, since it's an extra level of
indirection).


Removing the ref ups the time as described before, but only with GDC (DMD the 
runtime is the same).  It's a real effect.



There is no implicit local copy for const. I have a suspicion that you changed
two things and forgot about one of them when running your tests.


Really don't think so.  You can even check the version history of changes if you 
like!


Re: ref semantics with hashes

2012-05-02 Thread H. S. Teoh
On Wed, May 02, 2012 at 09:38:35PM +0200, Andrej Mitrovic wrote:
[...]
> So if the hash wasn't already initialized then the reference in the
> Foo struct is a reference to null, and if you duplicate that reference
> and add a key the old reference still points to null.
> 
> The only way to ensure a proper link with a hash is to initialize it
> with a key and then immediately remove that key, which makes the hash
> not-null but empty:
[...]
> Why do we have such error-prone semantics?

I was told that this was expected behaviour.

Should the new AA implementation change this, so that it always
allocates an empty AA upon instantiation?


T

-- 
For every argument for something, there is always an equal and opposite 
argument against it. Debates don't give answers, only wounded or inflated egos.


Re: cannot cast

2012-05-02 Thread Namespace

Can anyone tell me, why the this code

[code]
module RefTest.Ref;

import std.stdio : writeln;
import std.conv : to, toImpl;

T const_cast(T : Object)(const T obj) {
return cast(T) obj;
}

struct Ref(T : Object) {
private:
 T _obj;

public:
@disable
this();// { }

@disable
this(typeof(null));// { }

this(T obj) {
assert(obj !is null, "Object is null!");

this._obj = obj;
}

@property
inout(T) access() inout {
assert(this._obj !is null, "Access: Object is null!");

return this._obj;
}

	//alias access this; // dann kommt "Stackoverflow" oder 
"recursive expansion"

}

mixin template TRef(T : Object) {
	final Ref!(T) getRef(string file = __FILE__, size_t line = 
__LINE__) in {
		assert(this !is null, "Object is null! @ " ~ file ~ " in Line " 
~ to!(string)(line) ~ ".");

} body {
return Ref!(T)(this);
}

	final Ref!(const T) getRef(string file = __FILE__, size_t line = 
__LINE__) const in {
		assert(this !is null, "Object is null! @ " ~ file ~ " in Line " 
~ to!(string)(line) ~ ".");

} body {
return Ref!(const T)(this);
}

U opCast(U : Object)() {
return *(cast(U*) &this);
}

alias getRef this;
}

unittest {
bool instanceof(T : Object, U : Object)(const Ref!U obj) {
		//return const_cast(obj.access).toString() == 
typeid(T).toString();

const U o = obj.access;

return const_cast(o).toString() == typeid(T).toString();
}

class A {
mixin TRef!(A);
}

class B : A { }

class C : B { }

A a1 = new B();
A a2 = new C();

assert(instanceof!(A)(a1) == false);
assert(instanceof!(B)(a1));
assert(instanceof!(C)(a1) == false);

writeln(a1);

B b1 = cast(B) a1;

writeln(b1);

writeln();
}
[/code]

fails with:

[quote]
Fehler	3	instantiated from here: 
instanceof!(A,A)	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	76


Fehler	2	Error: template instance RefTest.Ref.const_cast!(A) 
error instantiating	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	62


Fehler	4	Error: template instance 
RefTest.Ref.__unittest1.instanceof!(A,A) error 
instantiating	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	76	


Fehler	1	Error: function 
RefTest.Ref.__unittest1.A.TRef!(A).opCast!(A).opCast () is not 
callable using argument types ()	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	7	

[/quote]

? Sounds like a bug.


Transforming a range back to the original type?

2012-05-02 Thread Jacob Carlborg
Is there a general function for transforming a range back to the 
original type? If not, would it be possible to create one?


--
/Jacob Carlborg


Re: Transforming a range back to the original type?

2012-05-02 Thread Matt Soucy

On 05/02/2012 05:01 PM, Jacob Carlborg wrote:

Is there a general function for transforming a range back to the
original type? If not, would it be possible to create one?



I believe std.array's array function does what you want.
-Matt


Re: ref semantics with hashes

2012-05-02 Thread Jonathan M Davis
On Wednesday, May 02, 2012 13:32:04 H. S. Teoh wrote:
> On Wed, May 02, 2012 at 09:38:35PM +0200, Andrej Mitrovic wrote:
> [...]
> 
> > So if the hash wasn't already initialized then the reference in the
> > Foo struct is a reference to null, and if you duplicate that reference
> > and add a key the old reference still points to null.
> > 
> > The only way to ensure a proper link with a hash is to initialize it
> > with a key and then immediately remove that key, which makes the hash
> 
> > not-null but empty:
> [...]
> 
> > Why do we have such error-prone semantics?
> 
> I was told that this was expected behaviour.
> 
> Should the new AA implementation change this, so that it always
> allocates an empty AA upon instantiation?

The way that AAs work in this regard is identical to how dynamic arrays work.

- Jonathan M Davis


Re: Transforming a range back to the original type?

2012-05-02 Thread Jonathan M Davis
On Wednesday, May 02, 2012 23:01:21 Jacob Carlborg wrote:
> Is there a general function for transforming a range back to the
> original type? If not, would it be possible to create one?

You mean that if you have something like

auto range = getRangeFromSomewhere();
auto newRange = find(filter!func(range), value);

you want to transform newRange back to the same type as range?

I don't believe that that's possible in the general case. For example, take

Array!int a = getArrayFromSomewhere(0;
auto range = a[];
auto newRange = find(filter!"a < 7"(range), 2);

The type of a[] is specific to Array!int, cannot be created externally from it, 
and is tightly coupled with the container. What if the container held the 
values [1, 7, 2, 9, 42, 0, -2, 4]? newRange would end up having [2 , 0, -2 , 
4], which doesn't correspond to any range of elements in the Array. So, how 
could you convert newRange to the same type as range? The best that you could 
do as far as I can tell would be to create a new Array!int, put those elements 
in it, and slice the container.

So, I don't see how you could really take an arbitrary range and convert it 
back to its original type. With a very specific set of types, you might be able 
to (e.g. take([1, 2, 4, 9], 3) could be converted back to int[] easily 
enough), but with all of the wrapping that goes on with ranges, even 
determining what type of range is being wrapped by another can't be done 
generically AFAIK, let alone getting the whole chain down to the original 
range, let alone somehow converting the wrapped range back to that type.

Take remove in std.container, for example. It will only take the container's 
range type or the result of take on the container's range type - and it had to 
special case take. And removing a range from a container would be classic 
example of where you need the original range type rather than a wrapper.

- Jonathan M Davis


Re: ref semantics with hashes

2012-05-02 Thread bearophile

H. S. Teoh:


I was told that this was expected behaviour.


It's trash behavior, bug-prone and not intuitive. It has the
worst qualities of both a struct and a class :-)



Should the new AA implementation change this, so that it always
allocates an empty AA upon instantiation?


Sounds like a possibility.

Bye,
bearophile


Re: Transforming a range back to the original type?

2012-05-02 Thread bearophile

Jacob Carlborg:
Is there a general function for transforming a range back to 
the original type? If not, would it be possible to create one?


The newly redesigned containers in Scala language are often able 
to do this, but this has required the use of a very advanced 
static type system, that is currently not in D (maybe there are 
ways to implement it with D templates, but it will require work 
to implement).
Currently there is array.array() that turns the range into a 
dynamic array.


Probably some types/data structures will have a way to turn a 
lazy range into one of them.


Bye,
bearophile


Re: ref semantics with hashes

2012-05-02 Thread Andrej Mitrovic
On 5/2/12, Jonathan M Davis  wrote:
> The way that AAs work in this regard is identical to how dynamic arrays
> work.

Yes but they're very different in other regards. For example, if you
add an element to one array it doesn't automatically add an element to
the other array:

int[] a = new int[](2);
auto b = a;
b ~= 1;
a ~= 2;  // boom, a is now a new array

writeln(a);  // [0, 0, 2]
writeln(b);  // [0, 0, 1]

This is different from hashes, where adding a new element doesn't
magically create a new hash:

int[int] ha = [0:0];
auto hb = ha;
hb[1] = 1;
writeln(ha);  // [0:0, 1:1]
writeln(hb);  // [0:0, 1:1]

But maybe this is more relevant to how nulls and references work
rather than anything about hashes.

In fact what would *actually* solve this problem (for me) is if/when
we have aliases implemented for this scenario:

import std.stdio;

struct Foo
{
   int[] hash;
}

void main()
{
Foo foo;
alias foo.hash hash2;

hash2[0] = 1;
writeln(foo.hash);  // [1:1]
writeln(hash2); // [1:1]
}

Hopefully we get that one day.


Re: cannot cast

2012-05-02 Thread Namespace

Other, shorter example:

[code]
import std.stdio, std.traits;

class A {
int val;

alias val this;

T opCast(T : Object)() {
writeln("FOO");

return to!(T)(this);
}
}

class B : A {

}

T to(T : Object, U : Object)(const U obj) {
return *(cast(T*) &obj);
}

T const_cast(T)(const T obj) {
return cast(T) obj;
}

void main () {
A a = new B();
a.val = 42;

writefln("a.val: %d", a.val);

B* b = cast(B*) &a;
writefln("*b.val: %d", b.val);

B b1 = to!(B)(a);
writefln("b1.val: %d", b1.val);

B b2 = cast(B) a;
writefln("b2.val: %d", b2.val);

const B b3 = cast(B) a;

B b4 = const_cast(b3);
}
[/code]

print:

alias_this_impl.d(24): Error: function 
alias_this_impl.A.opCast!(B).opCast () is

 not callable using argument types ()
alias_this_impl.d(44): Error: template instance 
alias_this_impl.const_cast!(B) e

rror instantiating

I'm not very skillful in such "template" stories. Maybe someone 
can help me?




Re: ref semantics with hashes

2012-05-02 Thread Andrej Mitrovic
On 5/3/12, Andrej Mitrovic  wrote:
> import std.stdio;
>
> struct Foo
> {
>int[] hash;
> }

Sorry that should have been int[int] there.


Re: Passing array as const slows down code?

2012-05-02 Thread bearophile

Joseph Rushton Wakeling:

Removing the ref ups the time as described before, but only 
with GDC (DMD the runtime is the same).  It's a real effect.


There is no implicit local copy for const. I have a suspicion 
that you changed
two things and forgot about one of them when running your 
tests.


Really don't think so.  You can even check the version history 
of changes if you like!


Then it's seems a compiler bug. Please, minimize it as much as
possible, and put it in Bugzilla.

Bye,
bearophile


Test if an enum value is in a range of a derived enum

2012-05-02 Thread Andrej Mitrovic
import std.stdio;

enum Base
{
One,
Two,
Three,
Four
}

enum Subset : Base
{
Two = Base.Two,
Three = Base.Three
}

void main()
{
Base base = Base.Four;
if (cast(Subset)base)
{
writeln("yes");
}
}

This writes "yes" so cast is a blunt tool that doesn't work in this
case. to!() doesn't work either (compile error, maybe I should file
this) .
My first attempt to implement this check was to use .min/.max of each
enum like so:

import std.stdio;

enum Base
{
One,
Two,
Three,
Four
}

enum Subset : Base
{
Two = Base.Two,
Three = Base.Three
}

void isSubset(Base base)
{
if (base >= Subset.min && base <= Subset.max)
writeln("yes");
else
writeln("no");
}

void main()
{
Base base1 = Base.Three;
Base base2 = Base.Four;
isSubset(base1);  // yes
isSubset(base2);  // no
}

But this is wrong, because Subset might only define "One" and "Four"
in which case "Two" and "Three" will also pass as a subset even though
they're not defined in Subset.

The alternative is to convert the enum to a string and then to the
Subset enum type via the to!() template:

import std.stdio;
import std.conv;

enum Base
{
One,
Two,
Three,
Four
}

enum Subset : Base
{
One = Base.One,
Four = Base.Four
}

void isSubset(Base base)
{
try
{
to!(Subset)(to!string(base));
writeln("yes");
}
catch (ConvException)
{
writeln("no");
}
}

void main()
{
Base base1 = Base.One;
Base base2 = Base.Two;
isSubset(base1);  // yes
isSubset(base2);  // no
}

This works but is arguably slow. Personally I'd love it if I could use
the in operator for this, e.g.:

Base base1 = Base.Two;
assert(base1 in Subset);

Anyone know of any other solutions?


Re: Test if an enum value is in a range of a derived enum

2012-05-02 Thread bearophile

Andrej Mitrovic:

This writes "yes" so cast is a blunt tool that doesn't work in 
this case. to!() doesn't work either (compile error, maybe I

should file this) .


Seems worth filing.



Anyone know of any other solutions?


Write your own function to perform the test, using a liner loop?

Bye,
bearophile


extern and opaque structs

2012-05-02 Thread James Miller
I'm doing C bindings and I have an opaque struct and an extern'd 
variable of the type of that struct. The problem is that dmd is 
complaining that the struct has no definition (which is true). 
Making it a pointer works (expected) but i can't do that because 
the interface is expecting an full struct.


Adding __gshared doesn't help.

I assume this is bug, since usage of extern means that I don't 
need to know the size, since it will be allocated in the C code, 
not the D code.


--
James Miller


Re: extern and opaque structs

2012-05-02 Thread Jonathan M Davis
On Thursday, May 03, 2012 07:00:21 James Miller wrote:
> I'm doing C bindings and I have an opaque struct and an extern'd
> variable of the type of that struct. The problem is that dmd is
> complaining that the struct has no definition (which is true).
> Making it a pointer works (expected) but i can't do that because
> the interface is expecting an full struct.
> 
> Adding __gshared doesn't help.
> 
> I assume this is bug, since usage of extern means that I don't
> need to know the size, since it will be allocated in the C code,
> not the D code.

If you're putting the struct on the stack, then you need the struct's 
definition. That's true in C/C++ as well as in D. You can get away without 
having the definitions to its _functions_, but you need the definition for the 
struct itself. The only time that you escape this is via pointers.

And I don't know how you can talk about the struct as being allocated in the C 
code if it's on the stack, except perhaps if it has pointers as member 
variables, in which case it's the memory for those member variables which is 
allocated in the C code. The entire struct is copied every time that it's 
passed to anything - unless you're using pointers, which you say you aren't.

- Jonathan M Davis