September 27, 2019
On Friday, 27 September 2019 at 17:26:02 UTC, Jonathan Marler wrote:
> On Thursday, 26 September 2019 at 17:51:16 UTC, shfit wrote:
>> Herb Sutter gave a pretty interesting talk on zero cost exceptions and RTTI.
>>
>> https://m.youtube.com/watch?v=ARYP83yNAWk
>>
>> Could this be an option for D to avoid @gc exceptions?
>
> Wow this is a really big deal.  Zero-overhead exception with no memory allocation.  Could be a big feature for D.

Well, IIRC modern C++ does not do memory allocation today, it uses a preallocated buffer.

What he is talking about is replicating Rust-style "Optional" union return values as throw/catch but implemented in registers only. So it is basically about reducing the amount of state that is transferred to the caller from the exception location with some hints of the implementation.

For D this will be difficult because D provides the exception chain.

I suggested register based throwing for D many years ago. Nothing new...



September 29, 2019
On Thu, Sep 26, 2019 at 10:55 AM shfit via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> Herb Sutter gave a pretty interesting talk on zero cost exceptions and RTTI.
>
> https://m.youtube.com/watch?v=ARYP83yNAWk
>
> Could this be an option for D to avoid @gc exceptions?

If C++ does this, and we want to extern(C++), then we will support this... An interesting question might be if we are able to get ahead of the curve. I found his talk very motivating.
September 30, 2019
Am Sun, 29 Sep 2019 18:57:21 -0700 schrieb Manu:

> On Thu, Sep 26, 2019 at 10:55 AM shfit via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>
>> Herb Sutter gave a pretty interesting talk on zero cost exceptions and RTTI.
>>
>> https://m.youtube.com/watch?v=ARYP83yNAWk
>>
>> Could this be an option for D to avoid @gc exceptions?
> 
> If C++ does this, and we want to extern(C++), then we will support
> this...
> An interesting question might be if we are able to get ahead of the
> curve. I found his talk very motivating.

It's a very interesting idea. In the end, what he proposes is to bake support for error codes into the language, but in a way which resembles exception handling.

I think reusing the return channel for error codes in a union-like way with the result value and a flag to discriminate is quite clever.

However, compared to exceptions your still trading no CPU-overhead in the success case and lots of overhead in the failure case for a little overhead in success and a little overhead in failure (the compiler always has to check the flag after calling such a function, to propagate the error further). But I'd think this is not a large problem: Performance sensitive code probably doesn't use exceptions anyway, cause in most cases where you can't afford this little overhead in the success case, you probably can't afford the large overhead exceptions cause in the failure case either. But still, we'd need some kind of benchmarks in the end.

I also like this idea a lot cause it makes exception-like error handling viable for betterC/ microcontroller environments.


So for his idea 1, implementing error value in a return channel: We should really experiment with that in D. We also have the benefit of already having nothrow...

For his idea 2&3 IIRC, we already have contracts and IIRC we already have a flag which simply aborts the application / calls the debugger on failure instead of throwing.

Regarding handling / not handling OOM to make more code nothrow: Seems interesting, but I'd have to think about it more, how it relates to D.

His idea 4, explicitly marking all calls which can throw in some way (try), seems to be something which should be easy to implement in D. It's probably 99% compatible with the current grammar, we just need to allow try without catch. (Not sure if we need try at expression level as well: `bool a = try foo();` vs `try bool a = foo();`) But it needs a DIP of course.



I'm not sure about the RTTI part: The downcast optimization is clever, but it only works if you can do whole-program-optimization (i.e. statically linked). Of course in embedded, this is the default case, so it is important and useful.

Still, you should also be able to just walk up vtables in a linked-list style. Then all RTTI you need is one field in the Vtable which always links to the parent vtable, and when casting, you do this:

class Foo{}
clas Bar: Foo{}

cast(Bar)foo =>

auto vtbl = foo.vtbl;
while (vtbl && vtbl != Bar.vtbl)
    vtbl = vtbl.parent();
if (vtbl)
    // cast sucessfull
else
    // cast failed

Which has very little overhead. The main drawback for hard-realtime is that the overhead is not bounded: It's O(n) where n is the inheritance depth of the runtime object (foo). In practice, you're probably walking 1-20 elements in a linked list, which should be fast. But you can't easily determine n statically, unless you know all possible types for foo.

(C++ probably can't do this because of multiple inheritance. Thinking about this, we probably also get problems when we want to cast to parent interfaces this way...)

-- 
Johannes
September 30, 2019
On Fri, Sep 27, 2019 at 07:13:36PM +0200, Timon Gehr via Digitalmars-d wrote: [...]
> > A "non-owning" pointer cannot be passed to free() (or equivalent).
> 
> Issue is you can have a non-owning pointer pointing to a data structure that contains owning pointers.
[...]
> [...] E.g., you can have two non-owning pointers to a Array!int and then one of them reassigns the array, while the other borrowed a pointer to one of its elements.

Could you give a specific example with pseudocode?  I'm having trouble understanding exactly what goes wrong here.  I got as far as:

	struct S {
		OwnerPtr!int value;
	}
	OwnerPtr!S s = allocate!S();
	S* s1 = s;	// borrow
	S* s2 = s;	// borrow

	int* elem = s1.value; // borrow from contained owning ptr
	s2.value = new OwnerPtr!int(123); // invalidates elem

Doesn't this just mean that non-ownership should be transitive? I.e., if you have a non-owning pointer to some data structure, then all OwnerPtr's in the data structure effectively become non-owned from your POV, so reassigning is illegal.


> Rust enforces no mutable aliasing exactly because reassigning something may cause the old value to be deallocated.

Doesn't that just mean that the borrowed pointer had a lifetime that exceeded the lifetime of the owning pointer?  Therefore, it was (retroactively) illegal to have borrowed that pointer in the first place, since you couldn't guarantee that the owning pointer wouldn't become invalidated.  Transitive non-ownership seems to be one way of dealing with this (though I'm not sure whether it's sufficient, or even consistent -- have to think about this more).


T

-- 
I am not young enough to know everything. -- Oscar Wilde
1 2
Next ›   Last »