Re: opDispatch and alias this

2018-06-25 Thread IgorStepanov via Digitalmars-d

On Tuesday, 26 June 2018 at 00:56:13 UTC, Jonathan M Davis wrote:

On Monday, June 25, 2018 23:13:12 Seb via Digitalmars-d wrote:
- Jonathan M Davis


I've tried to fix this issue. If briefly there is one collision:

Final alias this should be r-value:

static struct S
{
int i;
}

void test(ref S s) {}
auto val = Final!S(42);
assert (!__traits(compiles, test(val))); //val works as r-value

However should be able to mutate fields of val:

val.i = 24;
assert(val.i == 24); //should works

We may discard this case: for struct is value-type and head const 
should disable changing of fields. For example in C++ you can't 
declare instance of struct when you can not reassign instance, 
but can reassign a field.


Re: D is now catching C++ exceptions!

2016-01-21 Thread IgorStepanov via Digitalmars-d-announce

On Monday, 18 January 2016 at 22:26:56 UTC, Walter Bright wrote:

at least for 64 bit Linux. Other platforms to follow.

  https://github.com/D-Programming-Language/dmd/pull/5342

This is what Andrei and I call "enabling" technology, as it 
opens the door for many more uses of D, in this case better 
interoperability with existing C++ codebases.


Thanks to everyone who helped out with this, especially Elie, 
Iain, David and Andrei!


Also looking forward to getting this in GDC and LDC!

Andrei and I feel that better interoperability with C++ is a 
major strategic feature and advantage for D. As the recent 
thread with Manu's frustrations in doing it show, we still have 
a significant way to go. But I hope to push it forward hard in 
the next few months.


For the fearless who love working under the hood, extending the 
support to the rest of the platforms is a great way to 
materially contribute.


This is a good start and we should continue this work.
We need review our documentation about interfacing to C++ and 
clearly delineate the limits of our features.


For example we should say how do we may write D binding of C++ 
class.
How do we may inherit D-defined C++ class from external C++ 
class/interface?

When can we pass object of inherited class back to C++ code?
How do we may cast one extern(C++) class to another extern(C++) 
class in D?

In C++?
Which C++ features we support for different ABIs?


Also, I think, we need to implement linking to some C++ features 
(I'll help with this when I finish my alias this duty):
Linking to C++ overloaded operators (without moving their 
semantic to D).

C++ ctors/dtors.
Dynamic casting of C++ objects in D.
Maybe partial C++ RTTI support.


Re: extern(C++) multiple inheritence

2016-01-21 Thread IgorStepanov via Digitalmars-d
On Wednesday, 20 January 2016 at 00:45:34 UTC, Walter Bright 
wrote:

On 1/19/2016 1:59 PM, Daniel Murphy wrote:

On 19/01/2016 8:04 PM, Walter Bright wrote:

On 1/19/2016 12:34 AM, Daniel Murphy wrote:
Yeah, it never has.  No attempt has ever been made to make 
it work.


Actually, as I recall it was made to match what DMC++ 
generates for Win32.




Wasn't that from before we had extern(C++) classes?  I did the 
extern(C++)

single inheritance class layout but didn't touch interfaces.


We had COM, which was an earlier form of C++ class support.


BTW, in docs I saw the following example:
Calling D Virtual Functions From C++

```
Given D code like:

extern (C++) int callE(E);

extern (C++) interface E
{
int bar(int i, int j, int k);
}

class F : E
{
extern (C++) int bar(int i, int j, int k)
{
writefln("i = %s", i);
writefln("j = %s", j);
writefln("k = %s", k);
return 8;
}
}

void main()
{
F f = new F();
callE(f);
}
```

```
The C++ code to access it looks like:

class E
{
  public:
virtual int bar(int i, int j, int k);
};


int callE(E *e)
{
return e->bar(11,12,13);
}
```


In this example C++ class E hasn't fields and another stuff. What 
happens if I change E?


class E
{
  std::string s;
  public:
virtual int bar(int i, int j, int k);
int strageHash()
{
 return s.length() + bar(0, 0, 0);
}
};

int callE(E *e)
{
return e->strageHash();
}

AFAIK, D can't generate correct F layout. D doesn't know 
sizeof(E), D doesn't know E ctor (the second one is fixable).
As result, new F() object can be smaller that E and this code has 
an unexpected behaviour.
Ok, we aren't gods and we can't suggest something better 
(exclusive of moveing multiple inheritance and C++ layout to D :).
However we may and should alert user about this limitation and 
about another limitations like this.
And when we add a new C++-related feature, we should declare 
C++-side limitations, in the first place, because they can't be 
enforced by D compiler.


And have someone any ideas about C++ to D interface generator?






Re: Martin Nowak is officially MIA

2015-06-17 Thread IgorStepanov via Digitalmars-d

On Thursday, 18 June 2015 at 02:54:00 UTC, Morbid.Obesity wrote:

On Wednesday, 17 June 2015 at 16:16:09 UTC, berlin wrote:
well, read something to your world situation. take it from an 
old kufr that dos not want to live under islamic law:


http://www.jihadwatch.org/
http://www.thereligionofpeace.com/
http://www.barenakedislam.com/
http://schnellmann.org/Understanding_Muhammad_Contents.html

BTW, I think, our troll just advertised his resources. It was the 
main his goal.


Re: Martin Nowak is officially MIA

2015-06-17 Thread IgorStepanov via Digitalmars-d
On Thursday, 18 June 2015 at 02:22:13 UTC, Vladimir Panteleev 
wrote:
On Wednesday, 17 June 2015 at 18:35:48 UTC, Andrei Alexandrescu 
wrote:
With this we revoke Martin's role as release czar. His github 
access will remain the same for the time being.


I think that was unnecessarily harsh and unilateral, not to 
mention demotivating (to both Martin and any people who 
considered the role). What do you mean by for the time being 
exactly?



We are therefore looking for a new release czar.


I would like to ask, what can we improve in our tooling and 
infrastructure to lessen the burden on release czars? I know 
nightly builds have been discussed for years, and it would be 
great to take advantage of the multi-platform infrastructure of 
the current autotester for it, but it doesn't look like that's 
going to happen.


Sorry for this post but...
Is it possible to remove disscusiion about relligions, 
nationalities and relations of them?
This is international forum and we may allow only one kind of 
intolerance: we may hate programmers, which doesn't use D yet.


I am surprised that disscussion, started by one troll passersby, 
doesn't stopped now.
Camrades, do not answer to troll posts. Just ignore it. I do not 
understand how something can be to try to answer such posts 
dripping fat as that from which it started.


Re: Martin Nowak is officially MIA

2015-06-17 Thread IgorStepanov via Digitalmars-d
On Wednesday, 17 June 2015 at 02:16:37 UTC, Andrei Alexandrescu 
wrote:

Hello,


Martin has not replied to any communication for more than two 
weeks now, and I'm starting to fear something might have 
happened to him. If anyone in Berlin could get in touch with 
him and let me/us know he's alright, I'd appreciate it. It's 
okay if he's bothered about missing his flight to DConf or 
anything related, but the perspective of a more serious problem 
is worrisome.


We are therefore looking for a new release czar. Two would be 
even better to avoid similar problems in the future. Please let 
everybody know if interested.



Thanks,

Andrei


He returned back to github and posted some messages. End alarm:)


Re: forum.dlang.org, version 2 (BETA)

2015-06-04 Thread IgorStepanov via Digitalmars-d-announce

On Friday, 5 June 2015 at 01:52:07 UTC, Vladimir Panteleev wrote:

On Friday, 5 June 2015 at 01:48:20 UTC, Meta wrote:
How feasible is it to add code formatting for the web 
interface?


Not sure what you mean. Do you mean syntax highlighting for D 
code?


If you mean the rewrapping issues with forum.dlang.org, those 
should be fixed now. Code (and other text with hard line 
breaks) should be sent and displayed as-is.
Sorry if this question has been raised but is the reason for the 
inability to edit posts? Will be this feature implemented 
sometime?


Re: forum.dlang.org, version 2 (BETA)

2015-06-04 Thread IgorStepanov via Digitalmars-d-announce

On Friday, 5 June 2015 at 02:03:48 UTC, Vladimir Panteleev wrote:

On Friday, 5 June 2015 at 02:02:11 UTC, IgorStepanov wrote:
Sorry if this question has been raised but is the reason for 
the inability to edit posts?


Posts are not editable because once sent, they are relayed to 
the NNTP server, mailing lists, and users' email inboxes.



Will be this feature implemented sometime?


Only when it becomes possible to edit a sent email.


Ok, why we use email/NNTP server instead of simple database/file 
storage?
Do we use some free mail server, or we must support some old 
infrastructure?


Re: forum.dlang.org, version 2 (BETA)

2015-06-04 Thread IgorStepanov via Digitalmars-d-announce

On Friday, 5 June 2015 at 02:14:08 UTC, Vladimir Panteleev wrote:

On Friday, 5 June 2015 at 02:11:17 UTC, IgorStepanov wrote:
On Friday, 5 June 2015 at 02:03:48 UTC, Vladimir Panteleev 
wrote:

On Friday, 5 June 2015 at 02:02:11 UTC, IgorStepanov wrote:
Sorry if this question has been raised but is the reason for 
the inability to edit posts?


Posts are not editable because once sent, they are relayed to 
the NNTP server, mailing lists, and users' email inboxes.



Will be this feature implemented sometime?


Only when it becomes possible to edit a sent email.


Ok, why we use email/NNTP server instead of simple 
database/file storage?
Do we use some free mail server, or we must support some old 
infrastructure?


Yes, this forum was created explicitly to replace Web-News, an 
NNTP newsreader. Initially all communication was done via NNTP 
(Web-News or a desktop NNTP client) and mailing lists. The last 
time I checked, only 50% of posters used forum.dlang.org, 
others used NNTP or mailing lists.


Interestingly, they do it because they are accustomed, or they 
have a handy desktop/mobile applications?


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-06-04 Thread IgorStepanov via Digitalmars-d
Hello, comrades. Lets put into the schedule reviewing of this PR 
(https://github.com/D-Programming-Language/dmd/pull/3998).
It contains a very much changes and it is hard to maintain its 
performance: each foreign PR may break it.


Re: Better handling of noncopyable objects and objects with this(this)

2015-06-01 Thread IgorStepanov via Digitalmars-d

On Monday, 1 June 2015 at 04:43:20 UTC, Andrei Alexandrescu wrote:
FYI I just created 
https://issues.dlang.org/show_bug.cgi?id=14638 as one of 
possibly several language enhancements to improve usability of 
noncopyable types (most allocators are not copyable) and to 
enhance performance of objects that define this(this). -- Andrei

My last year's thoughts about that:
https://issues.dlang.org/show_bug.cgi?id=13492


Re: Proof of concept - library AA

2015-05-30 Thread IgorStepanov via Digitalmars-d

On Saturday, 30 May 2015 at 15:24:49 UTC, Adam D. Ruppe wrote:

On Saturday, 30 May 2015 at 14:10:35 UTC, IgorStepanov wrote:

   static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))


I briefly mentioned this at the dconf and thinking about it a 
bit more, I think there's only two cases where we want implicit 
construction: function argument lists and function return 
values. (The syntax doesn't really matter, but I'd do it 
similar to C++ and just slap an @implicit on a regular 
constructor).

What did people say about this idea?



Re: Proof of concept - library AA

2015-05-30 Thread IgorStepanov via Digitalmars-d
On Saturday, 30 May 2015 at 08:51:31 UTC, Vladimir Panteleev 
wrote:
On Saturday, 30 May 2015 at 08:50:21 UTC, Vladimir Panteleev 
wrote:

http://localhost/post/asvcbsvfcxznwypttojk@192.168.0.1


Sorry, working link: 
http://forum.dlang.org/post/asvcbsvfcxznwypttojk@192.168.0.1


We may say that AA!(K, V)* should be recognized as V[K] by 
compiler. However in this case we will found another problem: 
opIndexAssign will unable to allocate memory for the new AA 
instance, because it can't modify `this` pointer.
Otherwise, implicit casting _from_ another type is a unsolvable 
task now.
Please, remind, why we don't want to add possibility of implicit 
casting from another type (not as default constructor behaviour, 
of course)?

Something like

struct Foo
{
int a;
static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))
{
return Foo(val);
}
}


Re: Proof of concept - library AA

2015-05-30 Thread IgorStepanov via Digitalmars-d



struct Foo
{
int a;
static Foo opImplicitConstructFrom(T)(T val) if(is(T : int))
{
return Foo(val);
}
}


void test(Foo foo, int i)
{
assert(foo.a == i);
}

test(42, 42); -
test(Foo.opImplicitConstructFrom(42), 42);


Re: Proof of concept - library AA

2015-05-29 Thread IgorStepanov via Digitalmars-d

On Friday, 29 May 2015 at 11:17:00 UTC, Martin Nowak wrote:

On Wednesday, 27 May 2015 at 17:16:53 UTC, IgorStepanov wrote:

Foo f;
f[5][3] = Foo(42); translates to
   f.opIndex!(true)(5).opIndex!(true)(3) = Foo(42);

auto x = f[5][4]; translates to
   auto x = f.opIndex!(false)(5).opIndex!(false)(3);


We shouldn't replace opIndexAssign though, b/c default 
construction + assignment is more expensive than constructing 
in-place.


Sorry, I meant
f.opIndex!(true)(5).opIndexAssign(Foo(42), 3);


Re: Proof of concept - library AA

2015-05-29 Thread IgorStepanov via Digitalmars-d

On Friday, 29 May 2015 at 12:52:29 UTC, Martin Nowak wrote:

On Friday, 29 May 2015 at 11:22:53 UTC, IgorStepanov wrote:

Sorry, I meant
f.opIndex!(true)(5).opIndexAssign(Foo(42), 3);


Added to the ER.
https://issues.dlang.org/show_bug.cgi?id=7753#c6


Thanks, but unfortunately, writing enhacement request to bugzilla 
is equals to writing to /dev/null :)

I'll create a DIP about this, when I'll have a free time.
What do you want about this syntax? Maybe you may suggest a 
better solution?


Re: Proof of concept - library AA

2015-05-29 Thread IgorStepanov via Digitalmars-d

On Friday, 29 May 2015 at 17:52:58 UTC, Martin Nowak wrote:

On Friday, 29 May 2015 at 13:12:58 UTC, IgorStepanov wrote:
What do you want about this syntax? Maybe you may suggest a 
better solution?


The discussion drifts a little OT, if we have opIndexCreate, 
then the library AA can be more compatible, but it still won't 
be a drop-in replacement.


We went a long way in this direction and if we don't come to the 
result yet, that, I think, we haven't thought-out plan.


I suggest you to answer to the following two question:
1. What way to transit to the new AA would be acceptable?
You rejects my way (and I could not continue to work in the 
winter), and AFAIR you principial objection was: aaLiteral is 
non-@safe for the unsafe code and it is breakage. However, 
aaLiteral attributes hasn't checked by compiler, because it was 
used in e2ir. _d_assocarrayliteralTX is not @safe or pure, but aa 
can be used in @safe pure code. We may insert additional checks, 
see aaLiteral attributes, and raise deprecation message, if 
attributes are inacceptable.
If it is the last objection, we may repeat compiler-side part for 
the new AA template. Othrewice, lets invent another way.


2. What issues disallows us to implement full library AA? Except 
.stringof, .mangleof, and other compiler magic.
I see only two issues: opIndexCreate and building aa from 
literals.


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-05-29 Thread IgorStepanov via Digitalmars-d

On Friday, 29 May 2015 at 21:41:12 UTC, Andrei Alexandrescu wrote:

On 5/29/15 3:37 PM, IgorStepanov wrote:
On Tuesday, 26 May 2015 at 00:03:43 UTC, Andrei Alexandrescu 
wrote:

On 5/25/15 3:01 PM, IgorStepanov wrote:
Ok, I've applied your changes to the DIP page, and I'm 
starting to
rework my github PR. Sorry for the slow work (I'm very busy 
last time).

However I still working. Stay on line=)


Thanks. Please get this done and let's pull it in for 068. -- 
Andrei


I've finished preparing of the github PR. Now it is ready for 
review.


So https://github.com/D-Programming-Language/dmd/pull/3998 is 
the one? -- Andrei

Yep.


Re: Proof of concept - library AA

2015-05-29 Thread IgorStepanov via Digitalmars-d

On Friday, 29 May 2015 at 22:41:13 UTC, Martin Nowak wrote:

On Friday, 29 May 2015 at 21:58:16 UTC, IgorStepanov wrote:

I suggest you to answer to the following two question:
1. What way to transit to the new AA would be acceptable?


One that doesn't break any code, carefully deprecates necessary 
semantic changes, and provides an improved implementation.


You rejects my way (and I could not continue to work in the 
winter), and AFAIR you principial objection was: aaLiteral is 
non-@safe for the unsafe code and it is breakage.


The objection was too much code breakage for an inferior 
implementation.

https://github.com/D-Programming-Language/druntime/pull/934#issuecomment-66888409

We may insert additional checks, see aaLiteral attributes, and 
raise deprecation message, if attributes are inacceptable.


I recall a list of your demands.


1. open addressing
2. efficient construction, insertion and assignment (no extra 
copies or postblits)

3. fully CTFEable (includes storing literals in the data segment)
4. type and attribute correctness
5. get's rid of TypeInfo methods (toHash, opEquals, tsize)
6. GC NO_SCAN for values


1. It depends only on library AA implementation, not on 
dmd-druntime interaction.
2. This goal was achieved in my last AA version. Open addressing 
edition may get us troubles with it, but I think this troubles 
are solvable.
3. Storing CTFE literals was implemented in that implementation. 
Maybe not quite right, but the problem is also solvable.

4. This solution follows directly from template implementation.
5. Was done.
6. This problem is also solvable.

Now about backward compatibility:
AFAIR you pointed to the one breakage: the forced checking of 
attribute correctness.
I then entered into an argument with you, but I forgot, that the 
forced  attribute checking was disabled in the last edition:
Yes, aaLiteral gets attributes from the underlying code, and if 
AA constructor was unsafe, aaLiteral was unsafe too.
However, AssocArrayLiteralExp::toElem doesn't check the attribute 
correctness and constructing of unsafe or non-throwable AA from 
safe or throwable code was allowed.

Or I forgot about some other breakage cases?

2. What issues disallows us to implement full library AA? 
Except .stringof, .mangleof, and other compiler magic.
I see only two issues: opIndexCreate and building aa from 
literals.


- error messages
- attributes
- literals (especially polysemous initializers, i.e. 
ubyte[ubyte] aa = [0:1, 1:2])

- implicit tail const conversion Val[Key] - const(Val)[Key]
- lots of magic around making Key const
- delete aa[key]
- lots of other small details (grep for Taarray in 
src/expression.c)


This is a heavily used built-in type, we can't risk a rewrite 
that breaks lots of code.



- error messages
Is it a significant problem? If compiler allows correct code, 
disallows incorrect code and gets a clear error messages there 
there is no problem, I think. Of cource, we will need to write 
pretty error messages, implement correct .stringof in dmd (to 
writting type name as V[K], not as AA!(K, V).



- attributes
We will able to deprecate attribute violations in transitional 
version (with vtbl).


- literals (especially polysemous initializers, i.e. 
ubyte[ubyte] aa = [0:1, 1:2])

Yes, this is the first main trouble.


- implicit tail const conversion Val[Key] - const(Val)[Key]

May be we may add alias this-es for all all those variants?
Something like ...
struct AA(K, V)
{
alias getCKeyMval this;
alias getMKeyCval this;
alias getCKeyCval this;
@property {
ref AA!(const(K), V) getCKeyMval() { return 
*cast(typeof(return)*)this; }
ref AA!(K, const(V)) getMKeyCval() { return 
*cast(typeof(return)*)this; }
ref AA!(const(K), const(V)) getCKeyCval() { return 
*cast(typeof(return)*)this; }

}
}


- lots of magic around making Key const

The most count of them may be solved without language modifying.


- delete aa[key]

This case has gone one or two years ago.
Now for the following code...
int[int] aa;
delete aa[5];
... compiler writes me Error: cannot delete type int

- lots of other small details (grep for Taarray in 
src/expression.c)

We should start to try to find and solve them.
As I see, we now we need only two language change requirements: 
opIndexCreate and AA literal overloading.
The rest of the problems can be identified at the stage of 
parallel operation of both implementations.


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-05-29 Thread IgorStepanov via Digitalmars-d
On Tuesday, 26 May 2015 at 00:03:43 UTC, Andrei Alexandrescu 
wrote:

On 5/25/15 3:01 PM, IgorStepanov wrote:
Ok, I've applied your changes to the DIP page, and I'm 
starting to
rework my github PR. Sorry for the slow work (I'm very busy 
last time).

However I still working. Stay on line=)


Thanks. Please get this done and let's pull it in for 068. -- 
Andrei


I've finished preparing of the github PR. Now it is ready for 
review.


Re: Proof of concept - library AA

2015-05-27 Thread IgorStepanov via Digitalmars-d

On Wednesday, 27 May 2015 at 14:12:02 UTC, Martin Nowak wrote:
On Sunday, 24 May 2015 at 15:13:41 UTC, Vladimir Panteleev 
wrote:

Could you elaborate on what these magic semantics are?


and no easy solution exists for the ++aa[key1][key2] case.


Is this specific to the pre-increment? aa[key1][key2]++ is 
generally a useful pattern.


This applies to pre/post increment as well as assignment and 
opOpAssign.
When an lvalue is needed the compiler will call a special 
runtime function GetX to obtain an lvalue for aa[key1], i.e. 
the entry will be default initialized iff missing.
If the expression is an rvalue though (aa[key1][key2]), a 
missing key1 will trigger a range error.
In an opIndex(Key) you have no idea whether the whole 
expression I an lvalue or an rvalue.


IIRC the construction/assignment of a value is also handled 
specifically.


BTW, may be we should create DIP about opIndex extending?
What do you want about following?
Let, if opIndex is template, and the first template argument is a 
bool value, compiler should pass true, if this is a part of 
l-value expression:


struct Foo
{
Foo[] children;
this(int value)
{
this.value = value;
}
int value;

ref Foo opIndex(bool lvl)(size_t idx)
{
if (idx  children.length)
return children[idx];
static if (lvl)
{
children.length = idx + 1;
return children[idx];
}
else
{
throw new Exception(out of bounds);
}
}
}


Foo f;
f[5][3] = Foo(42); translates to
f.opIndex!(true)(5).opIndex!(true)(3) = Foo(42);

auto x = f[5][4]; translates to
auto x = f.opIndex!(false)(5).opIndex!(false)(3);


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-05-25 Thread IgorStepanov via Digitalmars-d
On Tuesday, 31 March 2015 at 20:01:14 UTC, Andrei Alexandrescu 
wrote:

On 3/31/15 7:28 AM, IgorStepanov wrote:
On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu 
wrote:

On 3/30/15 8:04 AM, Steven Schveighoffer wrote:

On 3/29/15 1:34 PM, IgorStepanov wrote:

1. We should reject types which use opDispatch and alias 
this at the

same time.


Why? Alias this has no filter. opDispatch can use template 
constraints.
It makes perfect sense to prefer opDispatch, unless it 
doesn't have a

valid match, and then use alias this instead.

For example, if I wanted to wrap a type so I can instrument 
calls to

'foo', I could do something like this:

struct FooWrapper(T)
{
  T t;
  alias t this;
  auto opDispatch(string s, A...)(A args) if(s == foo) {
writeln(calling foo); return t.foo(args); }
}

Why is this a bad use case?


The idea is to start restrictive and define interaction 
meaningfully

later based on compelling use cases. -- Andrei


Andrei, do you approve those changes? Can we move to work on 
my github PR?


I made a few editorial passes, no major changes. I think 
there's still a fly in the ointment. The resolution algorithm 
goes:


1. If xyz is a symbol (member, method, enum etc) defined inside 
typeof(obj) then lookup is done.
2. Otherwise, if xyz is a symbol introduced in the base class 
(where applicable), then lookup is done.

3. Otherwise, if opDispatch!xyz exists, then lookup is done.
4. Otherwise, alias this is attempted transitively, and if xyz 
is found, then lookup is done.

5. Otherwise an UFCS rewrite is effected.

This puts opDispatch in between inheritance and subtyping, 
which I think we discussed is inappropriate - alias this should 
be effectively subtyping.


If we're really convinced alias this means multiple subtyping, 
the inherited type should not have a special role. However, it 
simplifies a lot of things to give one particular subtype a leg 
up on all others. So I think this would work:


1. If xyz is a symbol (member, method, enum etc) defined inside 
typeof(obj) then lookup is done.
2. Otherwise, if xyz is a symbol introduced in the base class 
(where applicable), then lookup is done.
3. Otherwise, if xyz is found at least via either an 
opDispatch!xyz or alias this conversion, then lookup is done.

4. Otherwise an UFCS rewrite is effected.

Then you explain that if you find more than one possibility via 
opDispatch and alias this, that's an ambiguity error.


I noticed you do mention in the Limitations section that 
opDispatch and alias this cannot be simultaneously present, but 
that kind of contradicts your resolution algorithm.



Andrei


Ok, I've applied your changes to the DIP page, and I'm starting 
to rework my github PR. Sorry for the slow work (I'm very busy 
last time). However I still working. Stay on line=)


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-05-25 Thread IgorStepanov via Digitalmars-d

On Monday, 25 May 2015 at 23:36:00 UTC, Timon Gehr wrote:

On 05/26/2015 01:17 AM, IgorStepanov wrote:



My example:
auto foo(T)(){ return 1; }
auto foo(T)()if(is(T: int)){ return 2; }

struct Foo
{
//...
}
struct Bar
{
 Foo f;
 int i;
 alias i this;
}

auto ret = foo!Bar;
assert(ret == 2); //exactly the second function
...


(No, this actually raises an ambiguity error, but I see the 
point.)



After that, imagine, someone added alias intVal this to Foo.
Now there are many ways to convert Bar to int. However, user
don't know about it.

And if foo!Bar will start to return 1, it is very ugly 
situation.


I'm not convinced the alternative is better.

One can still do e.g.:

auto foo(T)()if(!is(typeof({static assert(is(T: int));}))){ 
return 1; }
auto foo(T)()if(is(typeof({static assert(is(T: int));}))){ 
return 2; }
Yes, we will able hack the situation: for example via 
__traits(compile, ...) or via is(typeof(...))
However all those hacks are known and in strange template 
behaviour we able to find all those places.


I think, error is not bad. Multiple alias this is a new feature, 
and this solution allows us to catch all error and safely try 
this feature. Later we will able to relax all rules, when we will 
sure that it is safe.


Re: Proof of concept - library AA

2015-05-25 Thread IgorStepanov via Digitalmars-d

On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:

Would be interesting to get some opinions on this.

https://github.com/D-Programming-Language/druntime/pull/1282


BTW, I have one idea. We may declare the AA ABI:
AA is a pointer to the next layout:

__vtbl
N bytes of data

and __vtbl is a pointer to a struct:
struct AAVTBL
{
size_t function() size; //returns the size of AA object: N + 
(AABTBL*).sizeof

void* get(void* aa, @somefields@)
//another function
}

And it we teach compiler to use this ABI, we may say that any 
type which follows this ABI is a correct associative array.
At the first stage, we may adapt the existing AA implementation 
to follow this ABI, and adapt the compiler to use it.
After that, we will adble to write library AA (which also follows 
this ABI), which may be constructed as general D type, and casted 
to AA later.





Re: Proof of concept - library AA

2015-05-25 Thread IgorStepanov via Digitalmars-d

On Sunday, 24 May 2015 at 15:13:41 UTC, Vladimir Panteleev wrote:

On Sunday, 24 May 2015 at 14:13:26 UTC, Martin Nowak wrote:

Would be interesting to get some opinions on this.

https://github.com/D-Programming-Language/druntime/pull/1282


Looks like a good step in the right direction.

Some questions about:

This provides a strong incentive to no longer use the magic 
semantics of the builtin AAs,


Could you elaborate on what these magic semantics are?


and no easy solution exists for the ++aa[key1][key2] case.


Is this specific to the pre-increment? aa[key1][key2]++ is 
generally a useful pattern.


The general idea that library aa has a vtbl, and standart AA 
fuctions like _aaGetX will access to our AA via vtbl.

Compiler will operate with aa via all those _aaGetX, _aaLen et c.
Thus aa[x][y]++; will work as early.


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-05-25 Thread IgorStepanov via Digitalmars-d

On Monday, 25 May 2015 at 22:32:55 UTC, Timon Gehr wrote:

On 03/29/2015 07:34 PM, IgorStepanov wrote:


3. is(T: B) should raise an error if there are many ways to 
convert T to B.


This is inconsistent with how 'is' works otherwise, and it 
breaks template constraints in annoying ways. (There is no 
SFINAE.)


auto foo()()if(true){ return 1; } // this is the one you want
auto foo()()if(a){ return 2; }// this is the one with is(T: 
B)


void main(){
foo(); // error
}

Is the intention that no types with multiple alias this paths 
to some type should be defined in the first place?


This problem was discussed early, and Andrey sad that is(D: B)
should raise a error, if D can be converted to B via multiple
ways.
I mostly agree with Andrey.
The my main argument: wrong convertion shouldn't be implicitly
hidden and I suggested return true even if there are many ways to
convertion.

My example:
auto foo(T)(){ return 1; }
auto foo(T)()if(is(T: int)){ return 2; }

struct Foo
{
//...
}
struct Bar
{
 Foo f;
 int i;
 alias i this;
}

auto ret = foo!Bar;
assert(ret == 2); //exactly the second function

After that, imagine, someone added alias intVal this to Foo.
Now there are many ways to convert Bar to int. However, user
don't know about it.

And if foo!Bar will start to return 1, it is very ugly situation.


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-03-31 Thread IgorStepanov via Digitalmars-d
On Monday, 30 March 2015 at 18:33:17 UTC, Andrei Alexandrescu 
wrote:

On 3/30/15 8:04 AM, Steven Schveighoffer wrote:

On 3/29/15 1:34 PM, IgorStepanov wrote:

1. We should reject types which use opDispatch and alias this 
at the

same time.


Why? Alias this has no filter. opDispatch can use template 
constraints.
It makes perfect sense to prefer opDispatch, unless it doesn't 
have a

valid match, and then use alias this instead.

For example, if I wanted to wrap a type so I can instrument 
calls to

'foo', I could do something like this:

struct FooWrapper(T)
{
   T t;
   alias t this;
   auto opDispatch(string s, A...)(A args) if(s == foo) {
writeln(calling foo); return t.foo(args); }
}

Why is this a bad use case?


The idea is to start restrictive and define interaction 
meaningfully later based on compelling use cases. -- Andrei


Andrei, do you approve those changes? Can we move to work on my 
github PR?


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-03-30 Thread IgorStepanov via Digitalmars-d
On Monday, 30 March 2015 at 15:04:20 UTC, Steven Schveighoffer 
wrote:

On 3/29/15 1:34 PM, IgorStepanov wrote:

1. We should reject types which use opDispatch and alias this 
at the

same time.


Why? Alias this has no filter. opDispatch can use template 
constraints. It makes perfect sense to prefer opDispatch, 
unless it doesn't have a valid match, and then use alias this 
instead.


For example, if I wanted to wrap a type so I can instrument 
calls to 'foo', I could do something like this:


struct FooWrapper(T)
{
   T t;
   alias t this;
   auto opDispatch(string s, A...)(A args) if(s == foo) { 
writeln(calling foo); return t.foo(args); }

}

Why is this a bad use case?

-Steve


You can split this code to two structs:

struct FooWrapper(T)
{
   struct FooDispatcher
   {
   auto opDispatch(string s, A...)(A args) {
   writeln(calling , s);
   }
   }
   FooDispatcher d;
   T t;
   alias t this;
   auto foo(string s, A...)(A args)
   {
  writeln(calling foo); return t.foo(args);
   }
}

FooWrapper!X x;
x.foo(1, 2); //FooWrapper.foo has been called
x.bar(1, 2); //FooWrapper.d.opDispatch has been called
X orig = x; //FooWrepper.t is returned.

===
Yes, this code is much more tricky, but it work as you wish.
opDispatch + alias this may deliver many problems, if one of 
those has more high priority then the other.
We want to implement alias this maximally strictly, and after 
that, try to find rules which may be safely relaxed.


Re: DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-03-29 Thread IgorStepanov via Digitalmars-d

On Sunday, 29 March 2015 at 08:03:37 UTC, deadalnix wrote:

On Saturday, 28 March 2015 at 19:52:15 UTC, IgorStepanov wrote:

http://wiki.dlang.org/DIP66

First I want to apologize for the long absence.
I was very busy for those months and now I ready to continue 
the work.


This DIP has been approved with three clarifications:
about is-expression, about opDispatch and about common 
inheritance.
I've reflected those clarifications in this DIP version, and 
if it is OK, I'll start adaptation of my github PR to this DIP.


Can you explain the change from current situation a bit ?


Do you mean changes from previous DIP version?
I've added three ideas to this version:
1. We should reject types which use opDispatch and alias this at 
the same time.
2. We want to semantic alias this at the same time as an 
inheritance (and disallow hidding of alias this-ed members by 
inherited members), but we shouldn't do this change now, because 
it may break a lot of existing code.
3. is(T: B) should raise an error if there are many ways to 
convert T to B.


If you ask about changes from current alias this implementation, 
this DIP introduces multiple alias this, and formally discribes 
different cases.


DIP66 1.2 (Multiple) alias this. Continuation of work.

2015-03-28 Thread IgorStepanov via Digitalmars-d

http://wiki.dlang.org/DIP66

First I want to apologize for the long absence.
I was very busy for those months and now I ready to continue the 
work.


This DIP has been approved with three clarifications:
about is-expression, about opDispatch and about common 
inheritance.
I've reflected those clarifications in this DIP version, and if 
it is OK, I'll start adaptation of my github PR to this DIP.


Re: DIP66 v1.1 (Multiple) alias this.

2014-12-23 Thread IgorStepanov via Digitalmars-d
On Saturday, 20 December 2014 at 21:25:28 UTC, Andrei 
Alexandrescu wrote:

On 11/2/14 6:57 AM, IgorStepanov wrote:

And there is dispute about is expression: see
http://forum.dlang.org/thread/ubafmwvxwtolhmnxb...@forum.dlang.org?page=5


OK, time to get this approved.

First, the current DIP doesn't seem to address this:

Walter and I would agree to making the presence of BOTH alias 
this
and opDispatch a compile-time error. That would break existing 
code

but not change semantics silently.


Far as I remember it was left to the discussion. Nobody objected 
to this issue, thus we may accept it. I think.


Any thoughts on this? Currently opDispatch gets priority over 
alias this, see lookup step 3 in section Semantics of 
http://wiki.dlang.org/DIP66. That's problematic because it puts 
opDispatch in _between_ normal subtyping via inheritance and 
alias this, which is supposed to be just as solid as 
inheritance.


I think the principled solution is to combine steps 2 and 4 
into step 2, i.e. alias this is as strong as inheritance. Any 
ambiguous symbols would be rejected.


The second possibility, less principled but probably practical, 
would be to swap steps 3 and 4. That way alias this has juuust 
a teensy bit a lower status than regular inheritance.


It looks nice, but it can greatly break the existing code. I 
suggest a postpone this issue and discuss the semantic order in a 
separate discusson/


The simplest thing (which Walter favors) is to make the 
presence of both opDispatch and alias this a compile-time 
error. That would break only a teensy amount of code if any, 
and would give us time to investigate the best approach when 
compelling use cases come about. So I suggest we move forward 
with that for this DIP.


Regarding the is-expression controversy in 
http://forum.dlang.org/thread/ubafmwvxwtolhmnxb...@forum.dlang.org?page=5:


First off, is(S : T) is a subtyping test - is S a non-proper 
subtype of T, or not? (Non-proper or improper subtyping: S is 
allowed to be identical to T). alias this is a mechanism that 
introduces subtyping. It follows that subtyping introduced via 
alias this must be detected with is-expressions.


Now, you give an example of subtyping where one or more two 
objects of the same supertype may be reached through two or 
more different paths. This is a well-known problem in subtyping 
(known as diamond hierarchy or repeated inheritance).


In the case of alias this, different objects of the same type 
may be reachable (or at least the compiler is unable to tell 
statically whether the objects are distinct or not). A correct 
but hamfisted solution would be to sever the subtyping 
relationship whenever the same type is reachable through 
multiple paths.


The versatility of alias this, however, suggests a better 
solution: if T is indirectly reachable as a supertype of S 
through more than one path and the subtyping is either tested 
(by means of an is-expression) or effected (by means of an 
implicit conversion), the compiler should issue a compile-time 
error asking the user to define an alias this DIRECTLY inside 
S, which takes precedence over indirect reachability and 
informs the type system which T of the several reachable ones 
is needed.


Please let me know of any thoughts. Thanks!


Summing up.
There are three way to process is(D: B) where D may be converted 
to B in several ways.

1. is(D: B) should return false: D is not subtype of B now.
2. is(D: B) should return true: D is subtype of B anyway.
3. is(D: B) should raise an error: let the user decide what he 
wants.


I strongly aganist the first way. It means that is(D: B) may 
absorb the real error, if it happens.

Now only two construction in D may absorb errors:
is(typeof(something)) and __traits(compiles, anything)).
I say absorb when compiler see the error, ignores it and 
changes way of compilation:

static if (noErrors)
correct branch
else
error branch

This situation may cause strage errors, code hijacking and other 
bad things, thus user should has a possibility to keep track of 
such cases.
is(typeof(something)) and __traits(compiles, anything)) is a 
special constructions to error handling and user and everyone 
understands what is expected.
is(D: B) is trusted construction and it can't create problems 
now. Let's leave it so.


The second way is better, I think. It doesn't absorb the error, 
it skip error but doesn't change the compilation way.
Error will be raised anyway when compiler will process code which 
use this casting.
void foo(D)(D obj) if (is(D: Base)) // compiler will skip the 
error here...

{
Base b = obj; //... but it will raise the error here.
}

The third way is correct too, I think. It raises error earlier, 
but I changes current `is` semantic. AFAIK, `is` doesn't raise 
errors now.



the compiler should issue
a compile-time error asking the user to define an alias this 
DIRECTLY
inside S, which takes precedence over indirect reachability and 
informs

the 

Re: DIP66 v1.1 (Multiple) alias this.

2014-12-05 Thread IgorStepanov via Digitalmars-d


Bump


Re: Operator Overloading in an Abstract Base Class

2014-11-20 Thread IgorStepanov via Digitalmars-d-learn

On Thursday, 20 November 2014 at 22:10:28 UTC, Nordlöw wrote:

In my module symbolic.d at

https://github.com/nordlow/justd/blob/master/symbolic.d

is it somehow possible to overload binary operator ~ on pairs 
of instances SPatt?


I'm asking because my current try at

https://github.com/nordlow/justd/blob/master/symbolic.d#L332

is not called in the unittest at

https://github.com/nordlow/justd/blob/master/symbolic.d#L347

Isn't it possible to do operator overloading in an abstract 
base-class?


Seq opBinary(string op)(Patt rhs)
{
static if (op == ~)
{
return seq(this, rhs);
}
else
{
static assert(false, Unsupported binary operator  ~ op);
}
}

As far I understood your question, you want to override opBinary 
in a derived class?
You can't do it directly, because opBinary is template and 
template can not be overriten. However, you may declare virtual 
non-template method for ~ and call it from opBinary.


And `static if (op == ~)` is not good. Use template constraint 
instead:


class Patt
{
// It is better then your static if.
// Compiler will raise better error message for incorrect 
operator.

Seq opBinary(string op)(Patt rhs) if (op == ~)
{
return opCatImpl(rhs);
}

protected Seq opCatImpl(Patt rhs) //you may override it in 
derived class

{
return seq(this, rhs);
}
}


Re: Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-16 Thread IgorStepanov via Digitalmars-d
On Sunday, 16 November 2014 at 09:28:25 UTC, Rainer Schuetze 
wrote:



On 15.11.2014 23:40, IgorStepanov wrote:

Do I any fundamental error in this code?
May be Bucket[] ret = new Bucket[len]; ret.ptr is not base 
pointer?


Yes, for arrays larger than 2kB, the allocation length 
information is placed before the actual data, and ret.ptr has 
an offset of 16 bytes into the allocation block. As a 
consequence, applying BlkAttr.NO_INTERIOR will very likely 
cause the block to be collected. NO_INTERIOR has no effect for 
smaller blocks.


That's why the existing AA code explicitely uses GC.malloc 
instead of new[].


Thank you very much. That explains a lot.


Re: Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-15 Thread IgorStepanov via Digitalmars-d
On Saturday, 15 November 2014 at 03:41:56 UTC, Steven 
Schveighoffer wrote:

On 11/14/14 8:56 PM, IgorStepanov wrote:
On Friday, 14 November 2014 at 23:49:00 UTC, ketmar via 
Digitalmars-d

wrote:

On Fri, 14 Nov 2014 23:23:17 +
IgorStepanov via Digitalmars-d digitalmars-d@puremagic.com 
wrote:



What does the NO_INTERIOR flag?
it stops GC to acknowledge pointers inside allocated area as 
anchors.
i.e. if there is no pointer to the head (first address) of 
allocated

memory, it is assumed to be garbage.

this way we have much less false pointers, and GC not doing
pointer-block conversions.

for buckets we certainly has head pointer and can't have 
pointers to
bucket elements without head pointer. so it's safe to tell 
GC that it

shouldn't do unnecessary work.


In other words, if buckets array will contain only uint-s 
there is no

reason to mark buckets with NO_INTERIOR?


In case ketmar's reply doesn't drive it home...

NO_INTERIOR means that the GC should NOT consider pointers to a 
block as valid references if those pointers don't point to the 
HEAD of the block. In other words, they point to the interior.


An example

int * x = new int;
*x = 5;
byte *b = cast(byte *)x;
b++; // b is now an interior pointer, yet x is not.

If we had marked x's block as NO_INTERIOR, we are fine as long 
as x remains. If we set x to null, there is a danger that the 
block is collected, and now b is dangling.


Now, this isn't a whole lot more efficient, you still have to 
look up what b points at and see that it has the flag set. BUT, 
where it DOES help is if you had some size_t somewhere on a 
stack, that happens to be the same value as b, the GC may think 
it's a pointer, but correctly not keep the block alive just for 
that false pointer. The larger the block, the more helpful 
NO_INTERIOR is.


-Steve


Thanks for explanations. I undersood that now. However I have got 
a strange bug with NO_INTERIOR.

I have the following function:
static Bucket[] newBuckets(in size_t len) @trusted pure nothrow
{
Bucket[] ret = new Bucket[len];

if (!__ctfe)
{
GC.setAttr(ret.ptr, GC.BlkAttr.NO_INTERIOR);
}
return ret;
}

The Bucket declaration has a two uint fields and one of those has 
a explicit initializer:


private enum uint EmptyBucket = uint.max;

static struct Bucket
{
uint depth;
uint index = EmptyBucket;

@property bool occupied() const
{
return index != EmptyBucket;
}
}

I call this function for creating new bucket array (in init() 
function, at first value inserting and at rehashing).
I don't create a copy, slice, I don't get a array pointer. Before 
array creating and rehashing I use buckets only for access by 
index. However I have got a error, when `index` field initializes 
with some strange value when newBuckets argument is very big. 
(buckets.length is big value). When I comment a 
GC.setAttr(ret.ptr, GC.BlkAttr.NO_INTERIOR); line, code start 
works fine.

Do I any fundamental error in this code?
May be Bucket[] ret = new Bucket[len]; ret.ptr is not base 
pointer?


Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-14 Thread IgorStepanov via Digitalmars-d

Recently I encountered the following problem.
I need a simple stack of uint.
I want to push uints back and pop it. I don't want to copy this 
stack and I want it to work fast.


In a first approximation, the problem seems easy.

uint[] my_stack;
my_stack.reserve(256);

my_stack ~= 1; //push
uint head = my_stack[$ - 1]; //top
my_stack.length--; //pop
my_stack ~= 2; //push

However, when I changes the length and append new elem to the 
array after it, array is reallocated.


Ok, good point. Seems reasonable. I might create slice of array 
copy before changing of the length. And by default changing array 
length or creating slice should cause an array reallocation at 
appending.


However I don't plan to copy or creating slices of this array, 
thus I need to some magic for avoid reallocation.


I've found a GC.BlkAttr.APPENDABLE flag at core.memory.

How ever it hasn't helped me.
Is there another way to do it without manually managing of memory?


Re: Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-14 Thread IgorStepanov via Digitalmars-d
On Friday, 14 November 2014 at 22:25:20 UTC, Dmitry Olshansky 
wrote:

15-Nov-2014 01:16, IgorStepanov пишет:

Recently I encountered the following problem.
I need a simple stack of uint.
I want to push uints back and pop it. I don't want to copy 
this stack

and I want it to work fast.

In a first approximation, the problem seems easy.

uint[] my_stack;
my_stack.reserve(256);

my_stack ~= 1; //push
uint head = my_stack[$ - 1]; //top
my_stack.length--; //pop


Just make push into:

my_stack.assumeSafeAppend();
my_stack ~= value;

To avoid relocations.

Thanks! Your magic is works!


Re: Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-14 Thread IgorStepanov via Digitalmars-d
On Friday, 14 November 2014 at 22:38:53 UTC, Steven Schveighoffer 
wrote:

On 11/14/14 5:25 PM, Dmitry Olshansky wrote:

15-Nov-2014 01:16, IgorStepanov пишет:

Recently I encountered the following problem.
I need a simple stack of uint.
I want to push uints back and pop it. I don't want to copy 
this stack

and I want it to work fast.

In a first approximation, the problem seems easy.

uint[] my_stack;
my_stack.reserve(256);

my_stack ~= 1; //push
uint head = my_stack[$ - 1]; //top
my_stack.length--; //pop


Just make push into:

my_stack.assumeSafeAppend();
my_stack ~= value;

To avoid relocations.



In actuality, you do not need this before every push. You only 
need it between a pop and a push.


I highly recommend not doing arrays-as-stacks, because you end 
up writing your own type.
I'm working on AssociativeArray implementation and I need to 
array which contains indices of free entries (entries is an array 
which contain Entry objects. When we need to find empty Entry to 
add a new value to the AA, we are getting the first element of 
the stack. (If the stack is empty, we need to add new element to 
entries). If entry has been removed from AA, it index is added to 
the stack).


Thus I don't want to add extra fields, and this stack is an 
encapsulated entity.




Re: Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-14 Thread IgorStepanov via Digitalmars-d

On Friday, 14 November 2014 at 23:12:05 UTC, IgorStepanov wrote:
On Friday, 14 November 2014 at 22:38:53 UTC, Steven 
Schveighoffer wrote:

On 11/14/14 5:25 PM, Dmitry Olshansky wrote:

15-Nov-2014 01:16, IgorStepanov пишет:

Recently I encountered the following problem.
I need a simple stack of uint.
I want to push uints back and pop it. I don't want to copy 
this stack

and I want it to work fast.

In a first approximation, the problem seems easy.

uint[] my_stack;
my_stack.reserve(256);

my_stack ~= 1; //push
uint head = my_stack[$ - 1]; //top
my_stack.length--; //pop


Just make push into:

my_stack.assumeSafeAppend();
my_stack ~= value;

To avoid relocations.



In actuality, you do not need this before every push. You only 
need it between a pop and a push.


I highly recommend not doing arrays-as-stacks, because you end 
up writing your own type.
I'm working on AssociativeArray implementation and I need to 
array which contains indices of free entries (entries is an 
array which contain Entry objects. When we need to find empty 
Entry to add a new value to the AA, we are getting the first 
element of the stack. (If the stack is empty, we need to add 
new element to entries). If entry has been removed from AA, it 
index is added to the stack).


Thus I don't want to add extra fields, and this stack is an 
encapsulated entity.


And if we talk about AA:
What does the NO_INTERIOR flag? Why the table (buckets array) is 
allocated with GC.calloc and NO_INTERIOR flag instead of new 
Entry[size];


Re: Dynamic array as stack and GC.BlkAttr.APPENDABLE

2014-11-14 Thread IgorStepanov via Digitalmars-d
On Friday, 14 November 2014 at 23:49:00 UTC, ketmar via 
Digitalmars-d wrote:

On Fri, 14 Nov 2014 23:23:17 +
IgorStepanov via Digitalmars-d digitalmars-d@puremagic.com 
wrote:



What does the NO_INTERIOR flag?
it stops GC to acknowledge pointers inside allocated area as 
anchors.
i.e. if there is no pointer to the head (first address) of 
allocated

memory, it is assumed to be garbage.

this way we have much less false pointers, and GC not doing
pointer-block conversions.

for buckets we certainly has head pointer and can't have 
pointers to
bucket elements without head pointer. so it's safe to tell GC 
that it

shouldn't do unnecessary work.


In other words, if buckets array will contain only uint-s there 
is no reason to mark buckets with NO_INTERIOR?


Re: C++ overloaded operators and D

2014-11-13 Thread IgorStepanov via Digitalmars-d

On Thursday, 13 November 2014 at 09:57:04 UTC, Marc Schütz wrote:
On Wednesday, 12 November 2014 at 21:17:42 UTC, IgorStepanov 
wrote:
On Wednesday, 12 November 2014 at 20:49:42 UTC, Marc Schütz 
wrote:
On Wednesday, 12 November 2014 at 19:32:32 UTC, IgorStepanov 
wrote:
On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz 
wrote:
On Wednesday, 12 November 2014 at 11:43:36 UTC, 
IgorStepanov wrote:
C++ and D provides different behaviour for operator 
overloading.
D has a opIndex + opIndexAssign overloads, and if we want 
to map opIndex to operator[], we must to do something with 
opIndexAssign.


operator[] can be mapped to opIndex just fine, right? Only 
opIndexAssign wouldn't be accessible from C++ via an 
operator, but that's because the feature doesn't exist. We 
can still call it via its name opIndexAssign.


operator and operator can't be mapped to D. Same for 
operator.


That's true. Maybe we can just live with pragma(mangle) for 
them, but use D's op... for all others?


Binary arithmetic operators can't be mapped to D, if them 
implemented as static functions:


Foo operator+(int a, Foo f); //unable to map it to D, 
because static module-level Foo opAdd(int, Foo) will not 
provide the same behaviour as operator+ in D.
Thus: C++ and D overloaded operators should live in 
different worlds.


Can't we map both static and member operators to opBinary 
resp. opBinaryRight members in this case? How likely is it 
that both are defined on the C++ side, and if they are, how 
likely is it that they will behave differently?


opBinary(Right) is a template-functions. You can't add 
previous declaration for it to struct:


//C++
struct Foo
{
 Foo operator+(const Foo);
};

Foo operator+(int, const Foo);

//D
extern(C++)
struct struct Foo
{
 Foo opBinary!+(const ref Foo); //???


I see...


}

Foo opBinary!+(int, const ref Foo); //???


But this would of course be opBinaryRight, and inside struct 
Foo.


What if
Foo operator+(const Bar, const Foo);?
Is it Foo.opBinaryRight, or Bar.opBinary, or both?


For a C++ class interfaced from D: opBinary() in whichever of 
the two classes it is defined.


For a D class interfaced from C++: choose one, preferably 
opBinary(), as it's the natural one.


It is too difficult, I think.
1. Compiler should generate static operator declaration (for 
linkage with C++) and method-wrapper.
2. We should use old non-template operators (like opAdd, opSub 
etc.) or introduce new kind of operators.
3. We should explain to the user how to use our operator bindings 
(explain to the user).


Anyway we may implement generic approach with pragma(mangle) now 
and add special rules for some operators if it be considered 
usefull. AFAIK, There are many objections aganist operators 
mapping are mentioned in n.g.


Re: C++ overloaded operators and D

2014-11-12 Thread IgorStepanov via Digitalmars-d

On Wednesday, 12 November 2014 at 02:37:52 UTC, deadalnix wrote:
On Tuesday, 11 November 2014 at 22:26:48 UTC, IgorStepanov 
wrote:

Now D provides very powerfull means to link C++ code with D.
However D doesn't allow to call C++ overloaded operators.
It's very annoying, because C++ code may don't provide 
non-operator analogues.
What we know about C++ overloadable operators? Overloaded 
operator in C++ is a trivial function/method with special 
name. Thus operator[](int) differs from op_index(int) function 
only by mangle.
C++ OO have a different behaviour from D OO (for example C++ 
allows different  and  operator overloads or static function 
fro binary operators), thus we should avoud the temptation of 
map C++ OOs to D OOs, or back.


Also D provides a pragma(mangle) which allows to redefine 
symbol mangle. It takes a string argument and redefine mangle 
to it:

pragma(mangle, foo) void bar();//bar.mangleof == foo

I suggest to modify pragma(mangle) to support C++ operators.
If argument of this pragma is identifier (for example 
cppOpAdd), the pragma applied to extern(C++) function or 
method, compiler mangle the function in accordance with this 
identifier.


//C++
struct Foo
{
   int operator[](int);
   //another fields
};

//D
extern(C++) struct Foo
{
   pragma(mangle, cppOpIndex) ref int op_index(int);
   //another fields
}

//using:
Foo f;
f.op_index(1)++; //OK, op_index is linked with Foo::operator[]
f[1]++; //Error, no special behaviour for op_index

I think this approach is simple, doesn't modify the language, 
can be easily implemented and usefull. Destroy!


Why would you want to go that road ? Souldn't extern(C++) 
struct mangle this the right way by themselves ?


C++ and D provides different behaviour for operator overloading.
D has a opIndex + opIndexAssign overloads, and if we want to map 
opIndex to operator[], we must to do something with opIndexAssign.
operator and operator can't be mapped to D. Same for operator. 
Binary arithmetic operators can't be mapped to D, if them 
implemented as static functions:


Foo operator+(int a, Foo f); //unable to map it to D, because 
static module-level Foo opAdd(int, Foo) will not provide the same 
behaviour as operator+ in D.
Thus: C++ and D overloaded operators should live in different 
worlds.


Re: C++ overloaded operators and D

2014-11-12 Thread IgorStepanov via Digitalmars-d

On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz wrote:
On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov 
wrote:
C++ and D provides different behaviour for operator 
overloading.
D has a opIndex + opIndexAssign overloads, and if we want to 
map opIndex to operator[], we must to do something with 
opIndexAssign.


operator[] can be mapped to opIndex just fine, right? Only 
opIndexAssign wouldn't be accessible from C++ via an operator, 
but that's because the feature doesn't exist. We can still call 
it via its name opIndexAssign.


operator and operator can't be mapped to D. Same for 
operator.


That's true. Maybe we can just live with pragma(mangle) for 
them, but use D's op... for all others?


Binary arithmetic operators can't be mapped to D, if them 
implemented as static functions:


Foo operator+(int a, Foo f); //unable to map it to D, because 
static module-level Foo opAdd(int, Foo) will not provide the 
same behaviour as operator+ in D.
Thus: C++ and D overloaded operators should live in different 
worlds.


Can't we map both static and member operators to opBinary resp. 
opBinaryRight members in this case? How likely is it that both 
are defined on the C++ side, and if they are, how likely is it 
that they will behave differently?


opBinary(Right) is a template-functions. You can't add previous 
declaration for it to struct:


//C++
struct Foo
{
Foo operator+(const Foo);
};

Foo operator+(int, const Foo);

//D
extern(C++)
struct struct Foo
{
Foo opBinary!+(const ref Foo); //???
}

Foo opBinary!+(int, const ref Foo); //???

May be some cases can be mapped to D, but these cases require 
special consideration.


I suggest a generic rule.

extern(C++)
struct struct Foo
{
pragma(mangle,  cppOpAdd)Foo op_add(const ref Foo);
}

extern(C++)
pragma(mangle,  cppOpAdd)Foo op_add2(int, const ref Foo);

Now, if you want to use this overloaded operators as D operators, 
you may wrap it to D operator-functions.


extern(C++)
struct struct Foo
{
pragma(mangle,  cppOpAdd) Foo op_add(const ref Foo);

Foo opBinary(string s)(const ref Foo rvl) if (s == +)
{
 return op_add(rvl);
}

Foo opBinaryRight(string s)(int lvl) if (s == +)
{
 return op_add2(lvl, this);
}
}

extern(C++)
pragma(mangle,  cppOpAdd)Foo op_add2(int, const ref Foo);

This way allows access to C++ operators and doesn't add new rules 
into the language.


Re: C++ overloaded operators and D

2014-11-12 Thread IgorStepanov via Digitalmars-d

On Wednesday, 12 November 2014 at 20:49:42 UTC, Marc Schütz wrote:
On Wednesday, 12 November 2014 at 19:32:32 UTC, IgorStepanov 
wrote:
On Wednesday, 12 November 2014 at 14:41:17 UTC, Marc Schütz 
wrote:
On Wednesday, 12 November 2014 at 11:43:36 UTC, IgorStepanov 
wrote:
C++ and D provides different behaviour for operator 
overloading.
D has a opIndex + opIndexAssign overloads, and if we want to 
map opIndex to operator[], we must to do something with 
opIndexAssign.


operator[] can be mapped to opIndex just fine, right? Only 
opIndexAssign wouldn't be accessible from C++ via an 
operator, but that's because the feature doesn't exist. We 
can still call it via its name opIndexAssign.


operator and operator can't be mapped to D. Same for 
operator.


That's true. Maybe we can just live with pragma(mangle) for 
them, but use D's op... for all others?


Binary arithmetic operators can't be mapped to D, if them 
implemented as static functions:


Foo operator+(int a, Foo f); //unable to map it to D, 
because static module-level Foo opAdd(int, Foo) will not 
provide the same behaviour as operator+ in D.
Thus: C++ and D overloaded operators should live in 
different worlds.


Can't we map both static and member operators to opBinary 
resp. opBinaryRight members in this case? How likely is it 
that both are defined on the C++ side, and if they are, how 
likely is it that they will behave differently?


opBinary(Right) is a template-functions. You can't add 
previous declaration for it to struct:


//C++
struct Foo
{
   Foo operator+(const Foo);
};

Foo operator+(int, const Foo);

//D
extern(C++)
struct struct Foo
{
   Foo opBinary!+(const ref Foo); //???


I see...


}

Foo opBinary!+(int, const ref Foo); //???


But this would of course be opBinaryRight, and inside struct 
Foo.


What if
Foo operator+(const Bar, const Foo);?
Is it Foo.opBinaryRight, or Bar.opBinary, or both?


C++ overloaded operators and D

2014-11-11 Thread IgorStepanov via Digitalmars-d

Now D provides very powerfull means to link C++ code with D.
However D doesn't allow to call C++ overloaded operators.
It's very annoying, because C++ code may don't provide 
non-operator analogues.
What we know about C++ overloadable operators? Overloaded 
operator in C++ is a trivial function/method with special name. 
Thus operator[](int) differs from op_index(int) function only by 
mangle.
C++ OO have a different behaviour from D OO (for example C++ 
allows different  and  operator overloads or static function 
fro binary operators), thus we should avoud the temptation of map 
C++ OOs to D OOs, or back.


Also D provides a pragma(mangle) which allows to redefine symbol 
mangle. It takes a string argument and redefine mangle to it:

pragma(mangle, foo) void bar();//bar.mangleof == foo

I suggest to modify pragma(mangle) to support C++ operators.
If argument of this pragma is identifier (for example cppOpAdd), 
the pragma applied to extern(C++) function or method, compiler 
mangle the function in accordance with this identifier.


//C++
struct Foo
{
int operator[](int);
//another fields
};

//D
extern(C++) struct Foo
{
pragma(mangle, cppOpIndex) ref int op_index(int);
//another fields
}

//using:
Foo f;
f.op_index(1)++; //OK, op_index is linked with Foo::operator[]
f[1]++; //Error, no special behaviour for op_index

I think this approach is simple, doesn't modify the language, can 
be easily implemented and usefull. Destroy!


D hackers requested. Dancing around postblit.

2014-11-05 Thread IgorStepanov via Digitalmars-d

Please try to solve this task:
We have a struct S.
S has a some kind of postblit (user-defined or inherited frome 
field) and destructor. S has a @disabled opAssign.
We have an unitialized allocated memory block whick mapped to a S 
array.

struct S
{
   //postblit and dtor here
}
S[] data; // contains a garbarge

void emplace()(ref S val, size_t i);

The task: we should write emplace function, which initializes 
i-th element of data with val;
This function shouldn't call any dtors for example for the old 
data[i] (which contains a garbarge).
This function should be transparent for attributes. For example, 
if S postblit is nothrow emplace should be nothrow too. If S 
postblit is not nothrow, S should't be nothrow.
This function should call postblit only one time and shouldn't 
call any other S special functions (opAssign, ctor etc.)


Re: D hackers requested. Dancing around postblit.

2014-11-05 Thread IgorStepanov via Digitalmars-d
On Wednesday, 5 November 2014 at 20:01:59 UTC, Adam D. Ruppe 
wrote:
If you're willing to make it @system or @trusted, you can just 
copy the data and call postblit manually:


extern(C) @safe int printf(in char*);

struct S {
~this() { printf(dtor\n); }
this(this) { printf(postblit\n); }

@disable S opAssign(S s);
}

S[] data;
void emplace(Struct)(ref Struct val, size_t i) {
// just blit the struct contents over
// (same thing normal assign does anyway)
(cast(ubyte*)(data[i]))[0 .. Struct.sizeof] = 
(cast(ubyte*)val)[0 ..  Struct.sizeof];

// call postblit
data[i].__postblit();
}

void main() {
data.length = 1;
S s;

emplace(s, 0);
}



Since it is a template, attribute inference should take care of 
nothrow, etc.


It was my first try :(
data[i].__postblit();
calls the user-defined postblit and only it.

struct Sx {
 ~this() { printf(dtor\n); }
 this(this) { printf(postblit\n); }

 @disable S opAssign(S s);
}

struct S
{
   Sx s;
}

data[i].__postblit(); //error: S hasn't __postblit member, but it 
need the postblit call for Sx
typeid(S).postblit(data[i]) works as needed, but doesn't save 
postblit attributes.


Re: D hackers requested. Dancing around postblit.

2014-11-05 Thread IgorStepanov via Digitalmars-d

FYI:
My second try:

void emplace(V1)(ref V1 dst, ref V1 src) @trusted if (is(V1 == 
struct))

{
static if (new_obj)
{
V1 tmp = cast(V1)src; //create copy and call postblit
static V1 init = V1.init;
//bitwise copy of object, which already postblitted
(cast(void*)dst)[0 .. V1.sizeof] = (cast(void*)tmp)[0 
.. V1.sizeof];


//initialize tmp with V1.init.
(cast(void*)tmp)[0 .. V1.sizeof] = (cast(void*)init)[0 
.. V1.sizeof];

}
}

This method do one extra dtor call for tmp, but it may be trivial 
because tmp is V.init.

However it is not a complete solution of the task.


Re: D hackers requested. Dancing around postblit.

2014-11-05 Thread IgorStepanov via Digitalmars-d
On Wednesday, 5 November 2014 at 20:33:40 UTC, Adam D. Ruppe 
wrote:
On Wednesday, 5 November 2014 at 20:19:03 UTC, IgorStepanov 
wrote:
data[i].__postblit(); //error: S hasn't __postblit member, but 
it need the postblit call for Sx


Hmm, we could perhaps do a recursive call with 
__traits(allMembers) and if it has a __postblit.


Good point. I'll try it. Thanks.


Re: DIP66 v1.1 (Multiple) alias this.

2014-11-03 Thread IgorStepanov via Digitalmars-d
* At the AliasThis declaration semantic stage, the compiler 
can

perform the initial checks and reject the obviously incorrect
AliasThis declarations. - it might be simpler (for the sake 
of
simplifying generic code) to just delay all error checking to 
the

first use.


I disagree with that. Current check is not recursive and 
prevent you

code from a silly errors:

struct X(T, V)
{
   T t;
   V v;
   alias t this;
   alias v this; //Error if is(T == V). However this code is
fundamentally broken, and this error should be raised as soon 
as possible.

}


The code is not fundamentally broken if alias this is never 
used. I agree rejecting the code compulsively is also sensible, 
ONLY if there is a simple way to write a static if condition to 
make the code work. Meaning:


struct X(T, V)
{
T t;
V v;
static if (please_fill_this)
alias t this;
static if (please_fill_this_too)
alias v this;
}

If the two conditions are too hard to write then it would be 
difficult to argue this point successfully.


This code can be rewritten as:

struct X(T, V)
{
T t;
V v;
alias t this;
static if (!is(V == T))
alias v this;
}


The code is not fundamentally broken if alias this is never
used.


I meant that when you say that X is a subtype of T and X is a 
subtype of V where you don't know what T and V are, it means you 
don't really know what you're doing. And that is an error and the 
compiler should inform you about it as soon as possible. However 
I may be mistaken.


Understood. All: okay to make alias this + opDispach applicable 
to the

same expression an error?

I think it will be nice.

I'm sending this now with these points, will make one more pass 
through

the DIP when I'm online again.

Ok, I'll wait.

And please, answer the question about the is-expression.


Re: DIP66 v1.1 (Multiple) alias this.

2014-11-03 Thread IgorStepanov via Digitalmars-d

On Monday, 3 November 2014 at 20:06:27 UTC, Marc Schütz wrote:

On Monday, 3 November 2014 at 15:39:42 UTC, IgorStepanov wrote:
I meant that when you say that X is a subtype of T and X is a 
subtype of V where you don't know what T and V are, it means 
you don't really know what you're doing. And that is an error 
and the compiler should inform you about it as soon as 
possible. However I may be mistaken.


IMO the behaviour should be analogous to name lookup for 
modules: there should be an error only on use. It's hard to 
come up with a non-artificial example, but I can imagine there 
are some valid use cases in generic code. It won't hurt to 
report the ambiguity error on use, while it could theoretically 
hurt to report it early, so I'd suggest to go with the former.


There are two cases:
1: when alias a this tries to override base class typeof(a)
2: when alias a this tries to override alias b this where 
is(typeof(a) == typeof(b))


The first check is hard to implement at lookup-time, because base 
classes are resolved before alias this.
The second check may be easely dropped (anyway alias this 
conflicts are resolved properly at lookup time).


Do you accept this scheme (remove the second check but still 
alive the first check)?


DIP66 v1.1 (Multiple) alias this.

2014-11-02 Thread IgorStepanov via Digitalmars-d

http://wiki.dlang.org/DIP66

I've applied some changes to it, however there are still some 
unresolved questions.



Here's my destruction:

* symbol can be a field or a get-property (method annotated 
with @property and taking zero parameters). - actually:


(a) the @property annotation is not necessary
(b) there may be one ore more parameters so long as they're all 
defaulted


So the text should be obj.symbol must be a valid expression.


Done.

* At the AliasThis declaration semantic stage, the compiler 
can perform the initial checks and reject the obviously 
incorrect AliasThis declarations. - it might be simpler (for 
the sake of simplifying generic code) to just delay all error 
checking to the first use.


I disagree with that. Current check is not recursive and prevent 
you code from a silly errors:


struct X(T, V)
{
   T t;
   V v;
   alias t this;
   alias v this; //Error if is(T == V). However this code is 
fundamentally broken, and this error should be raised as soon as 
possible.

}

class A : B
{
   B b;
   alias b this; //Error: super type (B) always hides 
aliasthised type B because base classes should be processed 
before alias this types.

}

* I don't think the pseudocode helps a lot. Better let's have a 
clear and precise specification (I've edited the lookup order 
into an ordered list).


Done.

* Regarding the lookup, opDispatch shouldn't come before alias 
this, or should come before base class lookup. Essentially 
alias this is subtyping so it should enjoy similar privileges 
to base classes. A different way to look at it is opDispatch is 
a last resort lookup mechanism, just one step above the UFCS 
lowering.


I agree with this suggestion, however it breaks an existing code.
opDispatch shouldn't come before base type lookup, because it 
will hide basic methods like toString.
opDispatch may come after alias this lookup, however it will 
fundamentally change program behaviour.


Current (implemented is released compiler) behaviour:
import std.stdio;

struct Base
{
string foo()
{
return Base.foo;
}
}

struct Derived
{
Base b;
alias b this;

string opDispatch(string s)()
{
return opDispatch;
}
}

void main()
{
Derived d;
writeln(d.foo()); //prints opDispatch
}

After your change this call will write Base.foo. And I see no 
way to add third transitional state to allow users rewrite 
those code correctly.
This changing will suddenly, without any warning, change a user 
code. I understand that this case is very rare however it may be.


And, TBH, this issue not relevant with multiple alias this :-)


* The DIP should specify the working of alias this as 
rewrites/lowerings, not pseudocode. Basically for each kth 
declaration alias symbolk this; the compiler rewrites 
obj.xyz as obj.symbolk.xyz and then does the usual lookup 
on that expression. That means the whole algorithms is applied 
again etc. If more than one rewrite typechecks, that's an 
ambiguity error.


Ok. I've removed pseudocode. Is it better now?

* IMPORTANT: The DIP must discuss rvalue vs. lvalue cases. The 
rewrite approach simplifies that discussion because it's clear 
what happens by simply reasoning about the rewritten 
expression. Lvalue vs. rvalue matters a lot practically. 
Consider:


struct A
{
private int x;
alias x this;
}

struct B
{
private int _x;
int x() { return x; }
alias x this;
}

Then x can be passed by reference, modified directly etc. for A 
but not for B.


Done. I've added corresponding chapter to the DIP and commit to 
the PR.


Re: DIP66 v1.1 (Multiple) alias this.

2014-11-02 Thread IgorStepanov via Digitalmars-d
And there is dispute about is expression: see 
http://forum.dlang.org/thread/ubafmwvxwtolhmnxb...@forum.dlang.org?page=5


Re: DIP66 - Multiple alias this

2014-10-29 Thread IgorStepanov via Digitalmars-d

On Tuesday, 28 October 2014 at 23:12:21 UTC, Meta wrote:

On Tuesday, 28 October 2014 at 22:55:24 UTC, IgorStepanov wrote:

You may see isFloatingPoint declaration in traits.d:
enum bool isFloatingPoint(T) = is(FloatingPointTypeOf!T)  
!isAggregateType!T;


This template explicitly says that T shouldn't be an aggregate 
type. Thus

std.math.isNaN(X)(X x) if (isFloatingPoint!X)
shouldn't accept a struct.


Although alias this is supposed to denote subtyping, here is a 
violation of the Liskov Substitution Principle; although S is a 
subtype of float, there are some cases where it's invalid to 
substitute an S for a float. This seems like a problem with 
alias this to me. As S is aliased to float, typeof(s.val) 
should be passed to isFloatingPoint if passing S fails.


Your issue is not relevant with alias this implementation.
isFloatingPoint is a library implemented trait, which uses 
compile-time reflections to for verifying the truth of the 
approval T is floating point type.
If you think that isFloatingPoint implemented incorrectly, you 
may start corresponding discussion.
Otherwice, if you think that std.math.isNaN should accept user 
types which may be converted to floating point type, you may 
discuss that.

If you want simply solve you problem you may define own
auto isNaN(T)(S!(T) arg)
{
return isNaN(cast(T)arg);
}


Re: DIP66 - Multiple alias this

2014-10-28 Thread IgorStepanov via Digitalmars-d
On Tuesday, 28 October 2014 at 02:07:23 UTC, Andrei Alexandrescu 
wrote:

On 10/24/14 6:05 AM, IgorStepanov wrote:
On Friday, 24 October 2014 at 06:04:24 UTC, Andrei 
Alexandrescu wrote:

On 10/19/14 2:00 PM, IgorStepanov wrote:

Bump.


I've made a few grammar and fluency edits to the DIP, and 
collected a
few thoughts while doing that. Will get back on this before 
too long.

-- Andrei


I've seen it. Thanks!
Waiting for a comments.


Coming soon. I've been under quite a bit of pressure as of late.

Should I add chapter about method overloading with alias this: 
it should

work (and works) as cross-module overloading. It should imply
This implies from the DIP but hasn't written explicitly.


Interesting. I think it should work like overloading of calls 
in base and derived classes.


Not really. Rules which define overloading class methods doesn't 
describe multiple inheritance case.
In single inheritance case alias this rule is similar with 
inheritance rule: derived overload set hides base base overload 
set:


struct A
{
void foo(string)
{
writeln(string);
}

void foo(int)
{
writeln(int);
}
}

struct B
{
void foo(double)
{
writeln(double);
}

A a;
alias a this;
}

B b;
b.foo(string); //error
b.foo(42); //called B.foo(double), not B.a.foo(int);

The second test is not similar to inherintance rules, but this 
case is not relevant with multiple alias this and it is already 
done.


When I said cross-module overloading, I told about case when C 
inherits (via alias this) A and B, both A and B have foo 
methods with different paramethers and compiler should resolve 
foo call:


struct A
{
void foo(string)
{
writeln(string);
}

void foo(int)
{
writeln(int);
}
}


struct B
{
void foo(double)
{
writeln(double);
}
}

struct C
{
 A a;
 B b;
 alias a this;
 alias b this;
}

C c;
c.foo(str); // OK, c.a.foo(string)
c.foo(4.2); //OK, c.b.foo(double);
c.foo(42); //Error: c.a.foo(int) or c.b.foo(double)?

BTW, similar case with multiple inheritance via interfaces works 
absolutely incorrect:


interface CA
{
final void foo(string)
{
writeln(string);
}

final void foo(int)
{
writeln(int);
}
}

interface CB
{
 final void foo(double)
 {
 writeln(double);
 }
}

class CC : CA, CB
{

}

auto cc = new CC();
cc.foo(xxx); //OK, called CA.foo(string)
cc.foo(42); //called CA.foo(int) without any warnings
cc.foo(4.2); //Error: unable to call CA.foo with double argument.

In other words, compiler choses the first base interface, uses 
its overload set and ignores other interfaces.



OT: Should `et\s?c\.?` be written as etc in English?
I thought that it should be written as et c., because et 
cetera. Or

is it an anachronism?


You can't go wrong with M-W: 
http://www.merriam-webster.com/dictionary/etc


Thanks.


Re: DIP66 - Multiple alias this

2014-10-28 Thread IgorStepanov via Digitalmars-d
On Tuesday, 28 October 2014 at 19:45:09 UTC, Andrei Alexandrescu 
wrote:

On 10/10/14 10:09 AM, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


Here's my destruction:

* symbol can be a field or a get-property (method annotated 
with @property and taking zero parameters). - actually:


(a) the @property annotation is not necessary
(b) there may be one ore more parameters so long as they're all 
defaulted


So the text should be obj.symbol must be a valid expression.

* At the AliasThis declaration semantic stage, the compiler 
can perform the initial checks and reject the obviously 
incorrect AliasThis declarations. - it might be simpler (for 
the sake of simplifying generic code) to just delay all error 
checking to the first use.


* I don't think the pseudocode helps a lot. Better let's have a 
clear and precise specification (I've edited the lookup order 
into an ordered list).


* Regarding the lookup, opDispatch shouldn't come before alias 
this, or should come before base class lookup. Essentially 
alias this is subtyping so it should enjoy similar privileges 
to base classes. A different way to look at it is opDispatch is 
a last resort lookup mechanism, just one step above the UFCS 
lowering.


* The DIP should specify the working of alias this as 
rewrites/lowerings, not pseudocode. Basically for each kth 
declaration alias symbolk this; the compiler rewrites 
obj.xyz as obj.symbolk.xyz and then does the usual lookup 
on that expression. That means the whole algorithms is applied 
again etc. If more than one rewrite typechecks, that's an 
ambiguity error.


* IMPORTANT: The DIP must discuss rvalue vs. lvalue cases. The 
rewrite approach simplifies that discussion because it's clear 
what happens by simply reasoning about the rewritten 
expression. Lvalue vs. rvalue matters a lot practically. 
Consider:


struct A
{
private int x;
alias x this;
}

struct B
{
private int _x;
int x() { return x; }
alias x this;
}

Then x can be passed by reference, modified directly etc. for A 
but not for B.


===

Congratulations on taking this to a DIP. It clarifies things 
really nice and it's an example to follow for future language 
changes.



Andrei


Thanks for answer, I hope, I'll able to to carefully consider 
your comments tomorrow.


Now I want to ask about the one thing.
What do you think about compatibility with existing alias this 
implementation?


For example you wrote: Regarding the lookup, opDispatch 
shouldn't come before alias this, or should come before base 
class lookup..

This requirement breaks the existing code.
We can apply this change in DIP, however if we want to apply this 
change to compiler, we should be careful. Moreover, I don't see 
the way to create deprecation path: old 
implementation-deprecated old implementation  new 
inmplementation - prohibited old implementation  new 
inmplementation.


If we will change the semantic order of proprerty resolving, we 
will not able to warn user about changes. Suddenly his code will 
be compiled in a different way.


And please comment my way to resolving is expression via 
alias-this:

http://forum.dlang.org/thread/ubafmwvxwtolhmnxb...@forum.dlang.org?page=5

Thanks for the DIP review.


Re: DIP66 - Multiple alias this

2014-10-28 Thread IgorStepanov via Digitalmars-d

On Tuesday, 28 October 2014 at 21:55:35 UTC, Meta wrote:

On Tuesday, 28 October 2014 at 20:09:07 UTC, IgorStepanov wrote:
And please comment my way to resolving is expression via 
alias-this:

http://forum.dlang.org/thread/ubafmwvxwtolhmnxb...@forum.dlang.org?page=5


Something else related to the discussion about `is` from this 
thread: 
http://forum.dlang.org/post/tulvmydnogbgebnxy...@forum.dlang.org. 
The following code:


import std.math;
import std.traits;

struct S(T)
if(isFloatingPoint!T)
{
T val;
alias val this;
}

void main()
{

auto s = S!float();
assert(isNaN(s));
s = 10.0;
assert(!isNaN(s));
}

Current fails to compile with this error:

Error: template std.math.isNaN cannot deduce function from
argument types !()(S!float), candidates are:

std/math.d(4171):std.math.isNaN(X)(X x) if
(isFloatingPoint!X)

Is this a problem with the current implementation of `alias 
this`, or should isFloatingPoint be changed so that it also 
accepts types that alias a floating point type?


You may see isFloatingPoint declaration in traits.d:
enum bool isFloatingPoint(T) = is(FloatingPointTypeOf!T)  
!isAggregateType!T;


This template explicitly says that T shouldn't be an aggregate 
type. Thus

std.math.isNaN(X)(X x) if (isFloatingPoint!X)
shouldn't accept a struct.


Re: DIP66 - Multiple alias this

2014-10-24 Thread IgorStepanov via Digitalmars-d
On Friday, 24 October 2014 at 06:04:24 UTC, Andrei Alexandrescu 
wrote:

On 10/19/14 2:00 PM, IgorStepanov wrote:

Bump.


I've made a few grammar and fluency edits to the DIP, and 
collected a few thoughts while doing that. Will get back on 
this before too long. -- Andrei


I've seen it. Thanks!
Waiting for a comments.
Should I add chapter about method overloading with alias this: it 
should work (and works) as cross-module overloading. It should 
imply

This implies from the DIP but hasn't written explicitly.

OT: Should `et\s?c\.?` be written as etc in English?
I thought that it should be written as et c., because et 
cetera. Or is it an anachronism?


Re: DIP66 - Multiple alias this

2014-10-24 Thread IgorStepanov via Digitalmars-d

On Friday, 24 October 2014 at 13:17:28 UTC, Meta wrote:

On Friday, 24 October 2014 at 13:05:54 UTC, IgorStepanov wrote:
On Friday, 24 October 2014 at 06:04:24 UTC, Andrei 
Alexandrescu wrote:

On 10/19/14 2:00 PM, IgorStepanov wrote:

Bump.


I've made a few grammar and fluency edits to the DIP, and 
collected a few thoughts while doing that. Will get back on 
this before too long. -- Andrei


I've seen it. Thanks!
Waiting for a comments.
Should I add chapter about method overloading with alias this: 
it should work (and works) as cross-module overloading. It 
should imply

This implies from the DIP but hasn't written explicitly.

OT: Should `et\s?c\.?` be written as etc in English?
I thought that it should be written as et c., because et 
cetera. Or is it an anachronism?


The convention is to write etc., with the period indicating 
that the rest of the word has been omitted. If it appears in 
the middle of a sentence, I don't capitalize the subsequent 
word as it doesn't really make sense, but I'm not sure what the 
actual convention is in that respect.


Thanks for the explanation:)


Re: DIP66 - Multiple alias this

2014-10-21 Thread IgorStepanov via Digitalmars-d

On Tuesday, 21 October 2014 at 08:17:19 UTC, Dicebot wrote:

On Sunday, 19 October 2014 at 21:00:29 UTC, IgorStepanov wrote:

Bump.


For me current description and PR look solid and safe enough to 
try.


We are waiting for an Andrey's Word. Walter, as I understand 
haven't unresolved objections.


Re: DIP66 - Multiple alias this

2014-10-19 Thread IgorStepanov via Digitalmars-d

Bump.


Re: DIP66 - Multiple alias this

2014-10-19 Thread IgorStepanov via Digitalmars-d

On Monday, 20 October 2014 at 00:23:46 UTC, Daniel N wrote:
On Wednesday, 15 October 2014 at 09:50:17 UTC, IgorStepanov 
wrote:
In first edition I've implemented rule, when if type defines 
alias this directly, this alias hides all indirect aliases 
with the same type. However Andrey said that we should 
implement the strictest rules as possible and maybe relax them 
later.
Thus I implemented current rules, but saved the old 
implemetation of search. After some time we will able to 
return to first rule. It's not hard.


I see, in order to prevent any accidental shadowing, maybe one 
can consider override alias this, if we decide to make a 
relaxed version in the future?


Make sense. I think we should postpone but not forgotten this 
feature.
When main part will be merged, we will able to start discussion 
about override alias this.


What about the other features?


Re: Postblit bug

2014-10-17 Thread IgorStepanov via Digitalmars-d

On Friday, 17 October 2014 at 14:18:31 UTC, monarch_dodra wrote:
On Friday, 17 October 2014 at 00:55:25 UTC, ketmar via 
Digitalmars-d wrote:

On Fri, 17 Oct 2014 00:42:24 +
IgorStepanov via Digitalmars-d digitalmars-d@puremagic.com 
wrote:



Can someone comment this code? Should I think that it's a bug.
it's just an anomaly. const postblit can do alot of things 
besides
adjusting struct fields, and it's logical that compiler cannot 
call

non-const methods for const objects.

yet it's still on of those unforseen consequences that 
arises from

conjunction of different features.

i don't think that it's a bug, but i think that this must be 
discussed

anyway, and then documented.


AFAIK, Kenji has submitted a DIP, and has begun working on 
fixing the const/immutable/inout posblit issue.


However, there are some very subtle corner cases, so (afaik) 
work is slow.


To be honest, I think people use const way too much in D. 
It's *not* the C++ head const you can use anywhere. It's really 
just the base attribute between mutable and immutable data. 
In particular, due to the transitive nature of const, any time 
you use const it means you can't modify this, or anything 
produced or acquired from this, ever. It's usually not what 
people think they are signing for...


When it makes little sense to have your type as immutable, then 
I don't think you should bother much


What happends if we will ignore const/immutable modifier for 
postblits? Is it create any holes?


Re: Postblit bug

2014-10-17 Thread IgorStepanov via Digitalmars-d
On Friday, 17 October 2014 at 15:20:50 UTC, ketmar via 
Digitalmars-d wrote:

On Fri, 17 Oct 2014 14:41:36 +
IgorStepanov via Digitalmars-d digitalmars-d@puremagic.com 
wrote:


What happends if we will ignore const/immutable modifier for 
postblits? Is it create any holes?
it will break const promise. i.e. const/immutable data is 
not really

immutable now, it can be modified.


It's just common words=)
I meant that when postblit is called when new object is being 
creating and doesn't exists for user code.

E.g.
const S v1 = v2;
Ok, v1 _will_ be const when it will be _created_.
However postblit can think that object is mutable, because it 
called before the first accessing to the object from user code.
Thus I ask about case when postblit may mutate a const object, 
which created before postblitted object and may been accessed 
from user code before this postblitting.


Re: Postblit bug

2014-10-17 Thread IgorStepanov via Digitalmars-d

On Friday, 17 October 2014 at 17:25:47 UTC, monarch_dodra wrote:

On Friday, 17 October 2014 at 16:19:47 UTC, IgorStepanov wrote:

It's just common words=)
I meant that when postblit is called when new object is being 
creating and doesn't exists for user code.

E.g.
const S v1 = v2;
Ok, v1 _will_ be const when it will be _created_.
However postblit can think that object is mutable, because it 
called before the first accessing to the object from user code.
Thus I ask about case when postblit may mutate a const object, 
which created before postblitted object and may been accessed 
from user code before this postblitting.


That's way too many words for a single sentence for me to 
understand ;)


Yes, my english is so bad:)


But maybe this answers your question?

Yes, I've understood.

TBH, I have got this error while I am working on new AA, and I 
want to fix it as posdible faster (one way or another).

I have the next code:
struct AssociativeArray(Key, Value)
{
...
   struct Entry
   {
  Key key;
  Value value;
  ...
   }
}
If key or value is a const struct with postblit I have got a 
error.

I don't need an any postblit in Entry.
Thus I suggest another solution:
Do not generate helper functions like __fieldPostBlit, if struct 
has a @disabled this(this);

Destroy it.


Re: Postblit bug

2014-10-17 Thread IgorStepanov via Digitalmars-d
On Friday, 17 October 2014 at 19:45:43 UTC, ketmar via 
Digitalmars-d wrote:

On Fri, 17 Oct 2014 19:39:39 +
IgorStepanov via Digitalmars-d digitalmars-d@puremagic.com 
wrote:



Thus I suggest another solution:
Do not generate helper functions like __fieldPostBlit, if 
struct has a @disabled this(this);

Destroy it.

`@disable this (this);` means that struct can't be copied. it's
irrelevant what code compiler generates behind our backs, it 
will not
be executed anyway, 'cause compiler will complain: Error: 
struct XXX is

not copyable because it is annotated with @disable.


This error will be raised if I try to copy the my struct. But I 
don't want to do it. Now the error raised when I define the 
struct.


Postblit bug

2014-10-16 Thread IgorStepanov via Digitalmars-d

I've found a strange postblit bug (or not a bug?):



struct A
{
this(this)
{
}
}

struct B
{
A a;
}


struct C
{
const B b;
}

void main()
{
C c;
}



When I try to compile it, compiler raises the error: (Error: 
mutable method testaa2.B.__fieldPostBlit is not callable using a 
const object)


If I mark this(this) as const (BTW, is this(this) const a 
correct definition?) error still raises.

When I tried to reduce this code, I've found the next:



struct A
{
this(this)
{
}
}

struct B
{
const A a;
}


void main()
{
B b;
}



Error: mutable method testaa2.A.__postblit is not callable using 
a const object


If I change this(this) to const, error has been lost.



struct A
{
this(this) const
{
}
}

struct B
{
const A a;
}


void main()
{
B b;
}



Can someone comment this code? Should I think that it's a bug.


Re: Postblit bug

2014-10-16 Thread IgorStepanov via Digitalmars-d
On Friday, 17 October 2014 at 00:55:25 UTC, ketmar via 
Digitalmars-d wrote:

On Fri, 17 Oct 2014 00:42:24 +
IgorStepanov via Digitalmars-d digitalmars-d@puremagic.com 
wrote:



Can someone comment this code? Should I think that it's a bug.
it's just an anomaly. const postblit can do alot of things 
besides
adjusting struct fields, and it's logical that compiler cannot 
call

non-const methods for const objects.

yet it's still on of those unforseen consequences that arises 
from

conjunction of different features.

i don't think that it's a bug, but i think that this must be 
discussed

anyway, and then documented.


I think, this is unexpected behaviour:

Compiler generates __fieldPostBlit for all structs, and call it 
when postblit is needed.


In this example compiler generates something like the next code:

struct A
{
this(this)
{
}
}

struct B
{
A a;

void __fieldPostBlit()
{
a.__postblit(); //a has an explicit postblit
}
}


struct C
{
const B b;
void __fieldPostBlit()
{
b.__fieldPostBlit(); //Error: b is const
}
}

void main()
{
C c;
C c2 = c; //=
  //memcpy(c2, c, C.sizeof)
  //c2.__fieldPostBlit();

}


However, __postblit and __fieldPostBlit are always called for new 
object, thus it can neglect const guarantee and generate 
postblits like:

void __fieldPostBlit()
{
 (cast()b).__fieldPostBlit();
}


Re: DIP66 - Multiple alias this

2014-10-15 Thread IgorStepanov via Digitalmars-d

On Wednesday, 15 October 2014 at 03:49:41 UTC, Daniel N wrote:

On Wednesday, 15 October 2014 at 02:46:05 UTC, Dicebot wrote:
On Tuesday, 14 October 2014 at 12:33:50 UTC, IgorStepanov 
wrote:

This code tell that C is subtype of A and C is subtype of B.
User can use this fact in his code:
void foo(B);

C c = new C;
foo(c); //Ok.
Of course, we shouldn't allow user to cast c to int:
int i = c; //wrong
However, user can explicitly cast c to his subtype, which is 
convertable to int:

int i = cast(B)c; //Ok
Summarizing, I disagree with suggestion disallow this code at 
type semantic stage.


I agree. It will also make possible to break already working 
disambugation of `foo(c)` kind but adding new `alias this` to 
one of subtypes independently. That sounds annoying.


I guess the best part of D is, you have the means to fix 
anything you disagree with yourself... I can add a static 
assert to my class and be happy.


I have another idea, we could define that the shortest 
conversion chain wins, analogous to type promotions, that makes 
it possible to contain the issue inside C.


class C
{
  A a;
  B b;

  int disambiguate_int()
  {
return a;
  }
  alias a this;
  alias b this;
  alias disambiguate_int this;
  static assert(__traits(compiles, {int _ = C.init;}), 
Ambiguous alias this);

}

i.e. this assert should pass.


In first edition I've implemented rule, when if type defines 
alias this directly, this alias hides all indirect aliases with 
the same type. However Andrey said that we should implement the 
strictest rules as possible and maybe relax them later.
Thus I implemented current rules, but saved the old implemetation 
of search. After some time we will able to return to first rule. 
It's not hard.


Re: DIP66 - Multiple alias this

2014-10-14 Thread IgorStepanov via Digitalmars-d

On Monday, 13 October 2014 at 15:21:32 UTC, Daniel N wrote:

On 10/11/2014 7:23 AM, IgorStepanov wrote:

class A
{
int i;
alias i this;
}

class B
{
int i;
alias i this;
}

class C
{
A a;
B b;
alias a this;
alias b this;
}


My preferred solution would be to reject the 2nd alias 
declaration outright.


I don't see any value in intentionally creating the above 
pattern, _if_ it occurs then it's most likely due to an 
unintentional side-effect of a re-factoring, thus it should 
error out as close as possible to the real error.


This code tell that C is subtype of A and C is subtype of B.
User can use this fact in his code:
void foo(B);

C c = new C;
foo(c); //Ok.
Of course, we shouldn't allow user to cast c to int:
int i = c; //wrong
However, user can explicitly cast c to his subtype, which is 
convertable to int:

int i = cast(B)c; //Ok
Summarizing, I disagree with suggestion disallow this code at 
type semantic stage.


Re: DIP66 - Multiple alias this

2014-10-13 Thread IgorStepanov via Digitalmars-d
On Monday, 13 October 2014 at 00:54:13 UTC, Steven Schveighoffer 
wrote:

On 10/12/14 7:16 PM, IgorStepanov wrote:
On Sunday, 12 October 2014 at 23:02:13 UTC, Steven 
Schveighoffer wrote:

On 10/10/14 6:10 PM, IgorStepanov wrote:



You can write foo(c.shadow); This isn't hard.
Ok, I understood you, let's listen to what others say


Right, you can get around it.

But the issue here is, that I feel like is(T: U) means (from 
dlang.org):


is ( Type : TypeSpecialization )
The condition is satisfied if Type is semantically correct 
and it is
the same as or can be implicitly converted to 
TypeSpecialization.


This means is(C : int) should indicate that C can implicitly 
convert
to int. But in your DIP, it does not. I think this is 
incorrect.




Hmm. I've written case (my previous post), when returning 
false from

is(T: S), where T has many pathes to S is dangerous.


OK, I didn't understand your case before, but I just got it.

I understand what you mean, but this isn't anything new -- one 
can cause weird problems by creating diamond-pattern interfaces 
also. I do not actually think it is dangerous, because one 
would not leave an error call in their code. So for a future 
change to a library to mystically make a function start 
working is not a danger, because said code wasn't sitting there 
broken in the first place.


I will note, that for diamond problem interfaces, the compiler 
seems to take a different track than your DIP:


interface A {}
interface B : A {}
interface C : A {}

class X : B, C {}

static assert(is(X : A));

void main()
{
A a = new C; // works, not sure if it's B.A or C.A
}

I know this is a different problem -- we aren't pointing at two 
different concrete implementations.


-Steve


This is fundamentally different situation: interfaces haven't a 
state, thus don't care what interface will be getted: B.C or C.C. 
Moreover, we can think that we have only one base C (like virtual 
inherited class in C++).

Alias this case requires a completely different approach.


Re: DIP66 - Multiple alias this

2014-10-12 Thread IgorStepanov via Digitalmars-d

On Sunday, 12 October 2014 at 08:36:05 UTC, Marc Schütz wrote:

On Sunday, 12 October 2014 at 04:31:22 UTC, Walter Bright wrote:

On 10/11/2014 7:23 AM, IgorStepanov wrote:

class A
{
  int i;
  alias i this;
}

class B
{
  int i;
  alias i this;
}

class C
{
  A a;
  B b;
  alias a this;
  alias b this;
}

void foo(T)(T arg) if(is(T : int))
{
  ...
}

foo(C()); //Should it pass or not?


There's a rule with imports that if the same symbol is 
reachable via multiple paths through the imports, that it is 
not an ambiguity error. Here, the same type is reachable 
through multiple alias this paths, so by analogy it shouldn't 
be an error.


It's the same type, but different symbols; actual accesses 
would be ambiguous. `is(T : int)` shouldn't evaluate to true if 
`int a = T.init;` would fail.


I found an example of a situation that is bothering me.
Let we have a persistence framework, which provides a storing D 
object in some persistence storage: DB, file et c.


In introduces paired functions store/load and special type 
PersistenceObject.


If stored type is subtype of PersistenceObject it converts to 
PersistenceObject and PersistenceObject.load(stream) called for 
loading object (and PersistenceObject.store(stream) for storing).
Otherwice if object can't be converted to PersistenceObject it 
should be serialized via serialize function (or deserialized 
via deserialize).


struct PersistenceFramework
{
   void store(T)(T arg) if (is(T : PersistenceObject))
   {
   PersistenceObject po = arg;
   arg.store(stream);
   }

   void store(T)(T arg) if (!is(T : PersistenceObject))
   {
   PersistenceObject po = arg;
   store(serialize(arg));
   }

   void load(T)(ref T arg) if (is(T : PersistenceObject))
   {
   PersistenceObject po = arg;
   arg.load(stream);
   }

   void load(T)(ref T arg) if (!is(T : PersistenceObject))
   {
   PersistenceObject po = arg;
   load(serialize(arg));
   }

   Stream stream;
}

/
And we have the next types which we want to store and load
*/

struct Role
{
...
}

struct User
{
   Role role;
   PersistenceObject po;
   //...
   alias role this;
   alias po this;
}

/*/

User u;
persistenceFramework.load(u)
//...
persistenceFramework.store(u);


/**/
Role is not subtype of PersistenceObject thus all works ok.
We can store User via User.po and load it again;

Some time later, Role designer decided that Role should be 
subtype of PersistenceObject and changed Role definition:


struct Role
{
...
PersistenceObject po;
alias po this;
}

Now, User can not be converted to PersistenceObject because there 
are two path to convert: User.po and User.role.po;
Storing code after this change will be copiled successfully (if 
we follow your is rule), however object will be tried to load 
via void load(T)(ref T arg) if (!is(T : PersistenceObject)).
Because object was saved via void store(T)(T arg) if (is(T : 
PersistenceObject)) at the previous program run, user will not 
be loaded succesfully. Moreover, you will get an strange 
unexpected program behaviour and will be hard to find real error 
cause.


/*/
And finally, if you want to check, if you Type _really_ can be 
converted to AnotherType, you can use the next check:


void foo(Type)(Type arg) if (is(typeof({AnotherType x = 
Type.init;})))

{

}



Re: DIP66 - Multiple alias this

2014-10-12 Thread IgorStepanov via Digitalmars-d
On Sunday, 12 October 2014 at 23:02:13 UTC, Steven Schveighoffer 
wrote:

On 10/10/14 6:10 PM, IgorStepanov wrote:
On Friday, 10 October 2014 at 21:26:49 UTC, Steven 
Schveighoffer wrote:



An example:

foo(T)(T t) if(is(T : int))
{
  someFuncThatTakesInt(t);
}

foo(T)(T t) if(!is(T : int)  is(T.shadow : int))
{
  someFuncThatTakesInt(t.shadow);
}

struct A
{
  int i;
  alias i this;
}

struct B
{
  int i;
  alias i this;
}

struct C
{
  A a;
  B shadow;
  alias a this;
  alias shadow this;
}

C c;
foo(c); // should compile, but I think your DIP makes it fail 
due to

ambiguity



You can write foo(c.shadow); This isn't hard.
Ok, I understood you, let's listen to what others say


Right, you can get around it.

But the issue here is, that I feel like is(T: U) means (from 
dlang.org):


is ( Type : TypeSpecialization )
The condition is satisfied if Type is semantically correct and 
it is the same as or can be implicitly converted to 
TypeSpecialization.


This means is(C : int) should indicate that C can implicitly 
convert to int. But in your DIP, it does not. I think this is 
incorrect.


-Steve


Hmm. I've written case (my previous post), when returning false 
from is(T: S), where T has many pathes to S is dangerous. However 
your words also contain the truth. I don't know what we need to 
do. Maybe we should raise error during is semantic? Please, 
read my example and say your opinion.


Re: DIP66 - Multiple alias this

2014-10-12 Thread IgorStepanov via Digitalmars-d
Advantage of ky way is a more strictness then your way: if 
function with if(is(T: S)) will be called, error will be raised 
at the first trying of convert T to S. And we don't give the 
opportunity of possible error to spread away from the place of 
origin.


Re: DIP66 - Multiple alias this

2014-10-11 Thread IgorStepanov via Digitalmars-d

On Saturday, 11 October 2014 at 00:00:48 UTC, Walter Bright wrote:

On 10/10/2014 4:23 PM, IgorStepanov wrote:
On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright 
wrote:
must be an error, even if one of C.a() or C.b() might be a 
better match.

This is how things work for template mixins and imports.

So it is.


Good!

The same rule applies for overloading.


I've implemented overloading:
https://github.com/D-Programming-Language/dmd/pull/3998/files#diff-17b22eae29e74ce6ec29037438b5031cR2136

Please, tell me, what changes should I make to the DIP as a 
result of yesterday's discussions.

And please, tell your opinion about is issue:

class A
{
   int i;
   alias i this;
}

class B
{
   int i;
   alias i this;
}

class C
{
   A a;
   B b;
   alias a this;
   alias b this;
}

void foo(T)(T arg) if(is(T : int))
{
   ...
}

foo(C()); //Should it pass or not?


DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d
On Friday, 10 October 2014 at 17:31:23 UTC, Steven Schveighoffer 
wrote:

On 10/10/14 1:09 PM, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.

Hm... not sure you need a DIP.

From page 231 of TDPL: A class could introduce any number of 
alias this declarations, thus subtyping any number of types.


-Steve


TDPL tells that multiple alias this should be allowed, but tell 
nothing about conflict resolving. General idea of this DIP is 
sistematize rules for alias this. Please comment this part. Maybe 
I've forgot some cases, maybe introduce dangerous semantic rule.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d


Which will now create an error in the wrong place. IMO, the 
'is' test should also fail.


-Steve


In this case, you will see the real error and will able to fix 
if. For example call foo(c.a); Otherwice, you possible error will 
be fixed without taking into account your opinions.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 20:29:43 UTC, Brian Schott wrote:

On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


There is an error in the wiki formatting in the second code 
block. (`{| class=wikitable` should not be there)


I don't see any problems with the actual content of the DIP.


Fixed. This is starnge implicit copy-paste of my text editor =/


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d
On Friday, 10 October 2014 at 20:47:45 UTC, Steven Schveighoffer 
wrote:

On 10/10/14 1:09 PM, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


This part:

void test()
{
C c;
int i = c; //Error: c.a.i vs c.b.i
}

static assert(is(C : int)); //Ok, because C is subtype of 
int anyway.


I think might be wrong. There is a lot of code out there that 
says, e.g.:


void foo(T)(T t) if(is(T : U))
{
  U u = t;
  ...
}

Which will now create an error in the wrong place. IMO, the 
'is' test should also fail.


-Steve


I thought exactly about this using case.

See:
You have a struct like this in first place:
struct A
{
int i;
alias i this;
}

struct C
{
A a;
string s;
alias a this;
alias s this;
}

And you have a template function in second place:
void foo(T)(T t) if(is(T : int))
{
...
}

void foo(T)(T t) if(is(T : string))
{
...
}


And you have the code it third place:
C c;
foo(c); //Error: what do you mean: foo!(T : string) or foo!(T : 
int)


Now, someone (A developer) changed the A definition:

struct A
{
int i;
alias i this;
}

struct B
{
int i;
alias i this;
}

struct C
{
A a;
B b;
string s;
alias a this;
alias b this;
alias s this;
}

And now, you code mystically start to works.
Attention: Infusing in one place conflict resolves conflict in 
another place.

It is danger, I think.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 20:44:11 UTC, Marc Schütz wrote:

On Friday, 10 October 2014 at 17:09:08 UTC, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


I understand that as a first step it was suggested to implement 
the strictest behaviour regarding conflicts, namely to disallow 
them entirely.


However, I think more permissive strategies are useful, like in 
this example:

https://github.com/D-Programming-Language/dmd/pull/3998#issuecomment-58570742

Conflict resolution can work like overload resolution, with 
different levels of matching and partial ordering.


There isn't hard to change resolving strategy. This will need to 
change one function definition.
Thus we able to implement strictest now and after some time of 
new feature using, relax the behaviour. This will not require 
significant efforts.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright wrote:

On 10/10/2014 10:09 AM, IgorStepanov wrote:

Please, comment it.


 static assert(is(C : int)); //Ok, because C is subtype of int
anyway.

Comment should say that C is implicitly convertible to int


Not really.
int i = C(); //conflict: c.a.i vs c.b.i (thus, C is not 
implicitly convertible to int)



struct Test1
{
int a;
int b;
alias a this;
alias b this; //Error: alias b this conflicts with 
alias a this;

}

DIP says this is obviously incorrect, but what rule is being 
applied? I suspect the rule here is if typeof(a)==typeof(b), 
then it is rejected.


What if typeof(a) is implicitly convertible to typeof(b), and 
vice-versa?


In current state, if typeof(a) is implicitly convertible to 
typeof(b), and vice-versa, compiler will accept this alias this 
declaration.

However error may be raised at alias this resolving stage.

Is alias this resolved before base class search, after base 
class search, or is it an error if both searches are successful?


In existing alias this implementation alias this resolved after 
base class search.  This DIP inherits it, thus now I suggest to 
check base classes before alias this. Is it acceptable? Should I 
add this into DIP?


If 'a' and 'b' both contain overloads for function foo, then it 
should behave like imports do (which is a bit complex).


Hmm. Now it works as I wrote it DIP pseudo-code:
struct A
{
void foo(string);
void foo(int);
}

struct B
{
void foo(double);
}

struct C
{
A a;
B b;
alias a this;
alias b this;
}

C.foo(test); //found only one acceptable foo: C.a.foo(string)
C.foo(5);  //1. Check a: found C.a.foo(int);
   //2. Check b: found C.b.foo(double);
   //3. Raise error: C.a.foo(int) vs C.b.foo(double) 
conflict

C.foo(5.0);//found only one acceptable foo: C.b.foo(double)

Is it Ok?

Essentially, the rules for multiple alias this should be the 
same as for multiple imports and multiple mixin templates. 
These rules work, and the consistency will be expected.


Where can I read about multiple mixin templates?


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d
On Friday, 10 October 2014 at 21:26:49 UTC, Steven Schveighoffer 
wrote:

On 10/10/14 5:15 PM, IgorStepanov wrote:
On Friday, 10 October 2014 at 20:47:45 UTC, Steven 
Schveighoffer wrote:

On 10/10/14 1:09 PM, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


This part:

void test()
   {
   C c;
   int i = c; //Error: c.a.i vs c.b.i
   }

   static assert(is(C : int)); //Ok, because C is subtype of 
int anyway.


I think might be wrong. There is a lot of code out there that 
says, e.g.:


void foo(T)(T t) if(is(T : U))
{
 U u = t;
 ...
}

Which will now create an error in the wrong place. IMO, the 
'is' test

should also fail.

-Steve


I thought exactly about this using case.

See:
You have a struct like this in first place:
struct A
{
int i;
alias i this;
}

struct C
{
A a;
string s;
alias a this;
alias s this;
}

And you have a template function in second place:
void foo(T)(T t) if(is(T : int))
{
...
}

void foo(T)(T t) if(is(T : string))
{
...
}


And you have the code it third place:
C c;
foo(c); //Error: what do you mean: foo!(T : string) or foo!(T 
: int)


I agree with all this.


Now, someone (A developer) changed the A definition:

struct A
{
int i;
alias i this;
}

struct B
{
int i;
alias i this;
}

struct C
{
A a;
B b;
string s;
alias a this;
alias b this;
alias s this;
}

And now, you code mystically start to works.


Why? It's just as confused as before, no?

The way the DIP reads, the call to foo(c) compiles, but the 
instantiation fails. This can cause subtle issues when you want 
to select an instantiation based on what it casts to.


An example:

foo(T)(T t) if(is(T : int))
{
   someFuncThatTakesInt(t);
}

foo(T)(T t) if(!is(T : int)  is(T.shadow : int))
{
   someFuncThatTakesInt(t.shadow);
}

struct A
{
   int i;
   alias i this;
}

struct B
{
   int i;
   alias i this;
}

struct C
{
   A a;
   B shadow;
   alias a this;
   alias shadow this;
}

C c;
foo(c); // should compile, but I think your DIP makes it fail 
due to ambiguity


-Steve


You can write foo(c.shadow); This isn't hard.
Ok, I understood you, let's listen to what others say


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 22:05:18 UTC, Timon Gehr wrote:

On 10/10/2014 07:09 PM, IgorStepanov wrote:

I've created DIP for my pull request.
DIP: http://wiki.dlang.org/DIP66
PR: https://github.com/D-Programming-Language/dmd/pull/3998

Please, comment it.


- C c;
int i = c; //Error: c.a.i vs c.b.i

static assert(is(C : int)); //Ok, because C is subtype of int 
anyway.


So now we can have 'subtypes' whose instances cannot be stored 
in variables of the 'base type'?


C++ allowed subtypes, which can not be casted to the base type 
(inheritance of two identical, non-virtual base classes).
Ok, I've wrote my position, understood your and wait the decision 
of the arbitrator:)


Such behaviour is inconsistent with both the reference 
implementation and the documentation (and the two happen to be 
mutually inconsistent on how 'is(:)' should behave as well. :o) 
)



- The following pseudo-code illustrates this: [...] Finally, 
if resultSet contains only one candidate, the compiler will 
accept it.


This process might very well never terminate but it could 
terminate in more cases if it did something better than the 
naive brute-force search. I.e. either report cycles or don't 
keep exploring around cycles, but just looping indefinitely on 
cycles like the following is IMO not a good course of action:


struct S{
alias get this;
T get(){ return T.init; }
}
struct T{
alias get this;
S get(){ return S.init; }
int x;
alias x this;
}

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


This case described in DIP below.
Recursion tree will be like:
s.get
   s.get.get -return, because T is already visited
s.x - win

Furthermore, the following code compiles now, but doesn't under 
the approach described in the DIP. Is this an actual regression 
your pull introduces or is there a bug in the pseudocode?:


class A{
alias x this;
int x;
}

class B: A{
alias y this;
int y;
}

void main(){
int x = new B();
}

The same issue also needs to be considered if A and B are 
structs instead and B has an additional alias this to an A (the 
solution might also be part of a fix for the cycle issue).


- If resultSet contains more then one candidates, the compiler 
raises an error.


struct A
{
   short s;
   alias s this;
}

struct B
{
   int i;
   alias i this;
}

struct C
{
   A a;
   B b;
   alias a this;
   alias b this;
}

long l = C(); //What do you suggest?


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 22:18:36 UTC, Timon Gehr wrote:

On 10/11/2014 12:07 AM, IgorStepanov wrote:
On Friday, 10 October 2014 at 21:25:17 UTC, Walter Bright 
wrote:


If 'a' and 'b' both contain overloads for function foo, then 
it should

behave like imports do (which is a bit complex).


Hmm. Now it works as I wrote it DIP pseudo-code:


The pseudo-code doesn't actually specify that the arguments the 
identifier is being called with are considered at all.



struct A
{
void foo(string);
void foo(int);
}

struct B
{
void foo(double);
}

struct C
{
A a;
B b;
alias a this;
alias b this;
}

C.foo(test); //found only one acceptable foo: C.a.foo(string)
C.foo(5);  //1. Check a: found C.a.foo(int);
   //2. Check b: found C.b.foo(double);
   //3. Raise error: C.a.foo(int) vs 
C.b.foo(double) conflict

C.foo(5.0);//found only one acceptable foo: C.b.foo(double)

Is it Ok?
...


That is the right behaviour. What happens in this case:

struct A{
void foo(int);
void foo(double);
}

struct B
void foo(string);
}

... // (struct C and calls as yours)


C.foo(test); //Ok, C.b.foo(string);
C.foo(5);  //Ok, C.a.foo(int);
C.foo(5.0);//Ok, C.a.foo(double);

Compiler simply tries to forward c.foo(ARG) - c.a.foo(ARG) and 
c.b.foo(ARG). If only one is correct, compiler will accept it. If 
both is correct, compiler will raise an error.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 22:50:25 UTC, Walter Bright wrote:

On 10/10/2014 3:20 PM, IgorStepanov wrote:
The same issue also needs to be considered if A and B are 
structs instead and
B has an additional alias this to an A (the solution might 
also be part of a

fix for the cycle issue).

- If resultSet contains more then one candidates, the 
compiler raises an error.


struct A
{
   short s;
   alias s this;
}

struct B
{
   int i;
   alias i this;
}

struct C
{
   A a;
   B b;
   alias a this;
   alias b this;
}

long l = C(); //What do you suggest?


The rule would be if:

   long l = C.a();
   long l = C.b();

both compile, then:

   long l = C();

must be an error, even if one of C.a() or C.b() might be a 
better match. This is how things work for template mixins and 
imports.

So it is.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

BTW.

Overloaded functions in PR resolves un-properly (raises error 
even if can be resolved correct function)

However it's easy to fix and I'll do it tomorrow.


Re: DIP66 - Multiple alias this

2014-10-10 Thread IgorStepanov via Digitalmars-d

On Friday, 10 October 2014 at 22:51:34 UTC, Walter Bright wrote:

On 10/10/2014 3:46 PM, Timon Gehr wrote:

On 10/11/2014 12:29 AM, Walter Bright wrote:

On 10/10/2014 3:06 PM, Timon Gehr wrote:

On 10/10/2014 11:25 PM, Walter Bright wrote:


Essentially, the rules for multiple alias this should be 
the same as for
multiple imports and multiple mixin templates. These rules 
work, and the

consistency will be expected.


Agreed. Do you suggest to overload alias this against 
imports and

mixin templates?


I hadn't thought of that (thanks for bringing it up). My 
first thought
is no. Alias this gets searched after those do, because it 
comes into

play only when the symbol isn't resolved in the scope.


This allows for symbol hijacking (this is also the current 
behaviour):


// ---

module m;
import std.stdio;
// void foo(int x){ writeln(hi from m); } // uncomment to 
hijack


// ---

module main;
import std.stdio;

struct T{
import m;
alias s this;
S s;
}


struct S{
void foo(int x){ writeln(hi from S); }
}

void main(){
T t;
t.foo(1);
}


Hmm. Good point. The alias this should be done before imports.


Symmetrically. You may use symbol from import, uncomment it in 
aliased type and hijack it.


Re: Any libunwind experts n da house?

2014-09-28 Thread IgorStepanov via Digitalmars-d
On Saturday, 27 September 2014 at 23:31:17 UTC, Andrei 
Alexandrescu wrote:

On 9/27/14, 1:31 PM, IgorStepanov wrote:
No, that for throwing from C++ into D: for catch an exception, 
we should
pass type_info object to special C++ runtime function. C++ 
runtime
determines, can throwed object type can be casted to asked 
type, and if
yes - allow catch it and do catcher code. If you will see the 
my
example, you will see that I do this manually: get throwed 
type_info and

compare its mangle with requested mangle. If we will make it as
possible, it will be work better, faster and  reliable. As 
bonus:

possibility to implement dynamic_cast over C++ classes.


If that's what's needed, definitely please do explore it! But I 
defer expertise to Walter. -- Andrei


Ok. Anyway, I can't work on this to the full extent, because I 
have a three D works (six pull requests), which are waiting for 
action from the D collaborators (UDA for modules PR reviewed and 
is waiting for approval, multiple alias this and new AA 
implementation are waiting for review).


However, I've seen this direction and I want to report a few 
points:
1. C++ type_info/TypeHandle for classes is located on -1 index of 
vtbl;
2. type_info layout aren't standartized (as expected) and differs 
in G++, VS and (probably) DMC and SunC.
3. type_info in C++ uses in many different cases, like 
dynamic_cast and excetion handling.
4. D doensn't generate type_info and it can cause danger 
situation. e.g.



//C++ code
class CppBase
{
public:
virtual void test() = 0;
};

class CppDerived : public CppBase
{
public:
void test();
};


void CppDerived::test()
{
std::cout  CppDerived::test()  std::endl;
}

void doTest(CppBase *obj)
{
obj-test();
CppDerived *dobj = dynamic_castCppDerived *(obj); 
//Attention!

if (dobj)
{
std::cout  casted  std::endl;
}
else
{
std::cout  fail  std::endl;
}
}

//D code

extern(C++) interface CppBase
{
void test();
}


class DDerived : CppBase
{
extern(C++) override void test()
{
writeln(DDerived.test());
}
}

extern(C++) void doTest(CppBase);

void main()
{
writeln(start test);
doTest(new DDerived()); //BOOM! segfault while processing 
dynamic_cast, because DDerived type_info is wrong.

writeln(finish test);
}


//Now my suggestions:
1. We can implement type_info generation as library template like 
GenTypeInfo(T). It will return valid type_info object for 
supproted platforms and null for platforms, which isn't supported 
yet.
2. Compiler will use this template to get type_info and push it 
into vtbl (at -1 position)
3. In situation, when compile need to use type_info (may be 
try-catch with C++ exceptions or dynamic_cast, it will be raise 
error if type_info isn't implemented)


This approach allows to move complex, platform-depended code from 
compiler to library. Also it allows to don't implement some 
platforms without user restrictions.


In conclusion: this is a g++ type_info definitions:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/cxxabi.h#L535

This has a flag __diamond_shaped_mask in __vmi_class_type_info, 
and __virtual_mask in __base_class_type_info.
D allows multiply inheritance for interfaces. In mapping to C++: 
Is this inheritance virtual? Should we set __diamond_shaped_mask 
is A: B, C; B : D; C : D (B, C, D is interfaces)?


Re: Any libunwind experts n da house?

2014-09-27 Thread IgorStepanov via Digitalmars-d
On Saturday, 27 September 2014 at 09:53:37 UTC, Jacob Carlborg 
wrote:

On 2014-09-23 19:37, Andrei Alexandrescu wrote:
We need a libunwind expert to figure out a good approach for 
handling

exceptions thrown by C++ code into D.


BTW, are you only interested in handling C++ exception, or are 
you interested in handling D exceptions in C++ as well?




Ideally D should just use the same exception mechanism as C++. 
I don't think a language change is necessary for this. Changes 
in the compiler, yes, but hopefully not in the language.


C++ exception mechanism uses C++ type_info objects. We can 
inherit object.Throwable from std::exception (through extern(C++) 
interface), override the what() method, but there are no way to 
generate C++ type_info for D class now. If we want to do a 
compiler support of C++ exceptions, we should implement and 
support another one non-standartized feature: type_info. BTW it 
allows to do dynamic_cast over C++ classes in D, but I think, 
nobody approve this suggestion, because it can be hard).


Re: Any libunwind experts n da house?

2014-09-27 Thread IgorStepanov via Digitalmars-d
On Saturday, 27 September 2014 at 18:33:24 UTC, Jacob Carlborg 
wrote:
On Saturday, 27 September 2014 at 11:34:32 UTC, IgorStepanov 
wrote:


C++ exception mechanism uses C++ type_info objects. We can 
inherit object.Throwable from std::exception (through 
extern(C++) interface), override the what() method, but there 
are no way to generate C++ type_info for D class now. If we 
want to do a compiler support of C++ exceptions, we should 
implement and support another one non-standartized feature: 
type_info. BTW it allows to do dynamic_cast over C++ classes 
in D, but I think, nobody approve this suggestion, because it 
can be hard).


Objective-C can do it somehow. If they can do it I'm sure we 
can as well.


--
/Jacob Carlborg


If someone from D commanders bless me, I can start to exploring 
and implementing std::type_info for D classes. If we made it, we 
will implement 50% of C++ exception handling.


Re: Any libunwind experts n da house?

2014-09-27 Thread IgorStepanov via Digitalmars-d
On Saturday, 27 September 2014 at 19:16:24 UTC, Andrei 
Alexandrescu wrote:

On 9/27/14, 2:53 AM, Jacob Carlborg wrote:

On 2014-09-23 19:37, Andrei Alexandrescu wrote:
We need a libunwind expert to figure out a good approach for 
handling

exceptions thrown by C++ code into D.


BTW, are you only interested in handling C++ exception, or are 
you

interested in handling D exceptions in C++ as well?


The more the merrier, but there's a large difference in 
importance. For the most part D code (new) will call into C++ 
code (old) so it's the C++ exceptions we're most worried about. 
-- Andrei


Can someone implement an C++ exception transparency? (when 
exception, throwed from C++ can be passed through D function and 
landed down in C++ code).
Then, if type_info is implemented, I will able to try to 
implement C++ exception catching.


Re: Any libunwind experts n da house?

2014-09-27 Thread IgorStepanov via Digitalmars-d
On Saturday, 27 September 2014 at 20:18:42 UTC, Andrei 
Alexandrescu wrote:

On 9/27/14, 12:53 PM, IgorStepanov wrote:
On Saturday, 27 September 2014 at 18:33:24 UTC, Jacob Carlborg 
wrote:
On Saturday, 27 September 2014 at 11:34:32 UTC, IgorStepanov 
wrote:


C++ exception mechanism uses C++ type_info objects. We can 
inherit
object.Throwable from std::exception (through extern(C++) 
interface),
override the what() method, but there are no way to generate 
C++
type_info for D class now. If we want to do a compiler 
support of C++

exceptions, we should implement and support another one
non-standartized feature: type_info. BTW it allows to do 
dynamic_cast
over C++ classes in D, but I think, nobody approve this 
suggestion,

because it can be hard).


Objective-C can do it somehow. If they can do it I'm sure we 
can as well.


--
/Jacob Carlborg


If someone from D commanders bless me, I can start to 
exploring and
implementing std::type_info for D classes. If we made it, we 
will

implement 50% of C++ exception handling.


Would that be for throwing exceptions from D into C++? I think 
we can postpone that for now. -- Andrei


No, that for throwing from C++ into D: for catch an exception, we 
should pass type_info object to special C++ runtime function. C++ 
runtime determines, can throwed object type can be casted to 
asked type, and if yes - allow catch it and do catcher code. If 
you will see the my example, you will see that I do this 
manually: get throwed type_info and compare its mangle with 
requested mangle. If we will make it as possible, it will be work 
better, faster and  reliable. As bonus: possibility to implement 
dynamic_cast over C++ classes.


Re: Any libunwind experts n da house?

2014-09-27 Thread IgorStepanov via Digitalmars-d
On Saturday, 27 September 2014 at 20:11:34 UTC, Iain Buclaw via 
Digitalmars-d wrote:

On 27 September 2014 10:53, Jacob Carlborg via Digitalmars-d
digitalmars-d@puremagic.com wrote:

On 2014-09-23 19:37, Andrei Alexandrescu wrote:


We need a libunwind expert to figure out a good approach for 
handling

exceptions thrown by C++ code into D.



BTW, are you only interested in handling C++ exception, or are 
you

interested in handling D exceptions in C++ as well?

One ugly hack is to register a terminate handler. Then in the 
handler
extract the necessary information from the exception, create a 
D exception

with this information and throw it as a regular D exception.

Throwing a D exception that should be catchable in C++ is a 
bit more tricky.
It's possible to wrap the a call to a D function in a 
try-catch block.
Convert the D exception to a C++ exception, then throw it 
using a function
part of the C++ exception runtime. The problem here is that 
C++ won't be
able to catch this exception because there's no personality 
function (or

similar) setup by the D compiler.

Ideally D should just use the same exception mechanism as C++. 
I don't think
a language change is necessary for this. Changes in the 
compiler, yes, but

hopefully not in the language.



Well, ObjC++ shares the same EH personality routines as C++, 
which

probably accounts for the compatibility. :)

Iain.


Is this way acceptable for D, or not. Why?


Re: Any libunwind experts n da house?

2014-09-26 Thread IgorStepanov via Digitalmars-d
On Thursday, 25 September 2014 at 13:58:23 UTC, Andrei 
Alexandrescu wrote:

On 9/25/14, 4:55 AM, Kagamin wrote:
On Wednesday, 24 September 2014 at 15:07:05 UTC, Andrei 
Alexandrescu wrote:
I wonder how difficult would be to create a wrapper class 
CppException

for everything derived from C++ std::exception.


Why not catch std::exception directly? Then you could generate 
code,

just like C++ compiler does it.


That would be a language change - right now D can only catch 
Exception objects.


Andrei


I've implemented an experemental framework to catching C++ 
exceptions from D.

https://github.com/IgorStepanov/D-CPP-Exception-Handle
It works with G++, and depends on unwind-cxx.h header, which 
has been stealed from libstdc++/libsupc++/. libsupc++ is a part 
of libstdc++ and this file can be found in libstdc++ sources. 
However, libstdc++ developers doesn't publish this header and it 
cannot be found in /usr/include/


This framework allows to call external C++ function and call 
exception, if good handler is passed. Also it can process 
polymorphic exceptions: in attached example I throws 
std::logic_exception and catches std::exception:


//C++

#include stdexcept

//test function
void throwEx(void *)
{
throw std::logic_error(Catch me, if you can);
}

//D
extern(C++) void throwEx(void *);

void main()
{
/*
code like ...
try
{
throwEx(null);
}
catch(std.exception val)
{
printf(exception: '%s'\n, val.what());
}

may be rewritten as
*/

Try!(throwEx)(
(CPPException!int ex)
{
printf(exception: '%d'\n, *ex.data);
return 0;
},
(CPPException!(stdexceptions.std.exception) ex)
{
printf(exception: '%s'\n, ex.data.what());
return 0;
}
);
}
//prints: exception: 'Catch me, if you can'


However, DMD can't pass С++ exceptions through D function 
(including extern(C++)). Thus, we cant pass delegate to Try 
function instead of  throwEx, but this trouble can be resolved, I 
think.


Re: Any libunwind experts n da house?

2014-09-24 Thread IgorStepanov via Digitalmars-d
On Tuesday, 23 September 2014 at 17:37:42 UTC, Andrei 
Alexandrescu wrote:
We need a libunwind expert to figure out a good approach for 
handling exceptions thrown by C++ code into D.


Is anyone fluent with libunwind?


Andrei


Is there plans to catching C++ exceptions in D?
What kind of C++ exceptions planned to catch in D?
For example C++ can throw primitive types exceptions, for example 
int.
Of cource, them can be wrapped into special D CPPException : 
Throwable, class, which contains string representation of C++ 
exception.
What about C++ polymorthic exceptions? AFAIK, C++ exception are 
throwing by-value, and catching by ref (to allow polimorthic 
catch). Where C++ calls destructor for exception? In catch block? 
In D GC handles an exception lifetime.

Is there any ideas about it?
P.S. I tell about user-side of catching C++ exceptions, not about 
implementation.


Re: Any libunwind experts n da house?

2014-09-24 Thread IgorStepanov via Digitalmars-d

On Wednesday, 24 September 2014 at 19:28:50 UTC, Andrei
Alexandrescu wrote:

On 9/24/14, 9:54 AM, Iain Buclaw via Digitalmars-d wrote:
On 24 September 2014 16:07, Andrei Alexandrescu via 
Digitalmars-d

digitalmars-d@puremagic.com wrote:
I wonder how difficult would be to create a wrapper class 
CppException for
everything derived from C++ std::exception. It would not save 
the exact

exception, but it would save its what() string and perhaps the
typeid().name(). A translator would create CppException 
objects from

std::exception objects and their derivatives.

How hard would that be? Please advise.



Thinking about it:

- Identifying a C++ exception, simple.


Noice.

- Identifying whether a D catch handler for a C++ exception 
object
matches, tricky - maybe.  ABI of structs being a potential 
maintenance
burden - though you'd hope that they only change ABI once 
every two
years or so. Second, determining that the C++ object being 
thrown and
catch handler we are examining match might be awkward from D.  
That is

something that needs investigation.


Yah. I'm thinking of simplifying assumptions, e.g. all C++ 
exceptions map to one single D type called CppException, and we 
can assume there's always a D handler on top of the stack. All 
the CppException saves is a copy of the what() message from the 
C++ exception.


However, for sure, the easiest thing that could be done *now* 
that
only needs a slight EH library tweak is using catch-all 
handlers to

recover from any language exception.

try {
  SomeCxxFuncThatMayThrow();
}
catch {
  // Recover, but without knowing what happened.
}

But I'd imagine you'd actually want information to come with 
your

caught exception, though. :)


Well even a catch like that would definitely be an improvement.


Andrei


I have one freaky example for you. This example can be
non-standart and danger but it works:
C++ side: http://pastebin.ru/PceYCOEq
special function catch exception, pass it to specified handler
and re-throw, if handler not found

D side: http://pastebin.ru/7FNBzXHw
D defines a special handler and pass it to catchException
result:
D code call C++ function

void throwEx(void *)
{
 throw 4;
}
and prints:
dside.CPPException!int.CPPException@(0): 4

Doesn't fire to me, please :)


Re: Any libunwind experts n da house?

2014-09-24 Thread IgorStepanov via Digitalmars-d
Now DMD doesn't support thorowing C++ exceptions through D 
function:


extern(C++)
void throwEx(); //compiled by G++ and throws exception

extern(C++)
void dFunc(void*)
{
   throwEx();
}


catchException(dFunc, ...); //terminate programm instead of 
catch it. Should be works in gdc




Re: Any libunwind experts n da house?

2014-09-24 Thread IgorStepanov via Digitalmars-d

On Wednesday, 24 September 2014 at 22:14:5 UTC, Andrei
Alexandrescu wrote:

On 9/24/14, 2:53 PM, IgorStepanov wrote:


I have one freaky example for you. This example can be
non-standart and danger but it works:
C++ side: http://pastebin.ru/PceYCOEq
special function catch exception, pass it to specified handler
and re-throw, if handler not found

D side: http://pastebin.ru/7FNBzXHw
D defines a special handler and pass it to catchException
result:
D code call C++ function

void throwEx(void *)
{
 throw 4;
}
and prints:
dside.CPPException!int.CPPException@(0): 4

Doesn't fire to me, please :)


Awesome! How do we make it standard and safe? -- Andrei

C++ hasn't standart abi(
If we talk about g++, this code has a one conspicuous trouble: I
don't know, how to correctly get a pointer to exception. Class
exception_ptr has getter for it, but it is private. I'll think
about another variants.
And I don't know about cxxabi.h standartness.
The second trouble: if we want to do something more exception
printing, we should get an exception pointer to user. However,
user shouldn't copy this pointer, because exception object will
be destroyed in cpp side.
Good news: this code (D side) can be generated by D compiler:
try
{
 // C++ exceptions danger
}
catch(CPPException!int e)
{
}
catch(CPPException!myException e)
{
}

Of course, only exact match of exception will be works. No
polymorphism.


Last Postblit Optimization and r-value ref

2014-09-21 Thread IgorStepanov via Digitalmars-d

I've created issue about last postblit call optimization (LPO):
https://issues.dlang.org/show_bug.cgi?id=13492
As I wrote in issue description, this optimization can solve 90% 
r-value reference issue.

Let's talk about remaining 10%.
There are remain two issue:
1. value argument causes full copying it to stack (can be 
important for a large structs and static arrays)
2. When r-value passed to auto-ref function (or simply: to any 
function by value) then this value becomes a l-value and can be 
passed to the next call as l-value ref:

void first(Foo f)
{
   second(f);
}

void second(Foo f)
{
  writeln(by value);
  globalFoo = f; //perform LPO
}

void second(ref Foo f)
{
  writeln(by ref);
  globalFoo = f; //can't perform LPO
}

first(Foo(42)); //passed to first by value, to second by ref and 
prints by ref


I suggest a small ABI change which can solve this issues without 
major language changes.


1. Let's pass all structs and static arrays by ref (Keeping a 
value semantic).
2. Let's forward value args (include passed by auto ref) to a 
value args of a next call


See, how it will works with this changes and LPO:

void second(ref Foo); [1]
void second(Foo); [2]

void first(Foo f)
{
   second(f);
   second(f);
}

Translates to:

void first(Foo f)
{
   Foo __tmp1 = f; //postblit is called
   second(__tmp1); //[2] is called, f passed by ref

   second(f); //[2] is called, f passed by ref, postblit isn't 
called because LPO

}

If second() writes f to any storage (e. g. struct field), f will 
be saved to this storage without postblit and dtor calls and 
struct copying (for the second call of second())


This changes allow us simulate r-value refs without major 
language changes.


Destroy!


  1   2   >