October 08, 2015
On Thursday, 8 October 2015 at 11:15:35 UTC, Ola Fosheim Grøstad wrote:
> On Wednesday, 7 October 2015 at 17:02:51 UTC, Paulo Pinto wrote:
>> On Wednesday, 7 October 2015 at 15:42:57 UTC, Ola Fosheim Grøstad wrote:
>>> Are you thinking about Rust, or some other language?
>>
>> All of the ones that explore this area. Rust, ATS, Idris, F*....
>
> Oh, yeah, sure. I wondered more if you were looking to adopt a language with substructural typing (beyond library types like unique_ptr) for production.


Not a chance.

In my little universe it is all about JVM and .NET languages, JavaScript for the browser and C++ for when there isn't any other way.

Those languages is where I am having fun now, besides mobile coding. But it is
just dabbling and reading papers about them, nothing serious.

It is really hard to keep up with JVM, .NET and occasional look into C++. The languages are easy when compared to the whole ecosystem, hence why I went silent.

Just decided to comment, as an explanation of what resource management is possible in modern versions of Java/.NET.

>
> I personally think that they future is with actor-based programming in combination with substructural/behavioural typing since it lends itself to distributed computing, multi core etc. The challenge is making a good language for it that is sufficiently performant and still allows breaking out actors to other computational units (computers/CPUs).

Microsoft Research had an actor-based language for awhile, Axum.

Many of the ideas are now in .NET.
http://blogs.msdn.com/b/maestroteam/archive/2011/02/28/the-state-of-axum.aspx

https://en.wikipedia.org/wiki/Axum_%28programming_language%29

http://download.microsoft.com/download/B/D/5/BD51FFB2-C777-43B0-AC24-BDE3C88E231F/Axum%20Programmers%20Guide.pdf

>
> But yeah, I think there is a paradigm shift coming in ~10-15 years maybe?

Substructural typing for sure as it is coming slowly mainstream now.

Several years ago it was just Agda, now there are several projects, including
companies like Microsoft looking at it.

>
>>> Are you thinking about more lintish tools that can give false positives, or something with guarantees that can be a language feature?
>>
>> What Herb Sutter demoed at CppCon as compiler validation to CoreC++.
>
> I've only seen the talks on youtube. I was under the impression that Microsoft had accurate and inaccurate analysers, but that the accurate ones were too slow on current C++ code bases. With more annotations to guide the analyser... yes, maybe.
>
> I assume Microsoft use analysers based on Boogie:
>
> http://research.microsoft.com/en-us/projects/boogie/

They use it on their driver validation tools.

>
>> I can imagine that depending on how well the community takes those guidelines, they might become part of C++20.
>
> I think this is needed, but adoption probably won't happen without IDE benefits.

Yep, but for all of us that aren't shaving off ms or squeezing one more byte into the cache line, it doesn't matter much.

--
Paulo
October 08, 2015
On Thursday, 8 October 2015 at 13:20:51 UTC, Paulo Pinto wrote:
> It is really hard to keep up with JVM, .NET and occasional look into C++. The languages are easy when compared to the whole ecosystem, hence why I went silent.

I've found getting a good understanding of C++11/14 to be a serious time sink, and that's just the language and standard library, which is pretty small. So I can understand those who just stick to a conservative C++ subset.

> Just decided to comment, as an explanation of what resource management is possible in modern versions of Java/.NET.

Thanks :-)

October 08, 2015
On Thursday, 8 October 2015 at 08:21:09 UTC, Kagamin wrote:
> On Tuesday, 6 October 2015 at 20:31:58 UTC, Jonathan M Davis wrote:
>> I don't think the problem is with structs. The problem is that programmers coming from other languages default to using classes. The default in D should always be a struct. You use a class because you actually need inheritance or because you want to ensure that a type is always a reference type and don't want to go to the trouble of writing a struct that way (and even then, you should probably just write the struct that way).
>
> Hmm... If we must emulate reference semantics manually, it feels like C++ with explicit references, pointers and all sorts of smart pointers, and obviates need for classes being reference types: just emulate reference semantics as we must do it anyway.

Maybe, but having classes be value generally makes no sense, because you can't use polymorphism with value types. Classes are inherently reference types given their semantics. Even in C++ that's the case. It's just that they don't separate out classes and structs the way we do. But classes that use inheritance have to be used as reference types or all you're doing is sharing implementation (which can be done easily enough without inheritance). You're not doing anything with polymorphism without references. So, the separation that D has makes a lot of sense. It's just that in some cases - namely where determinstic destruction is required - having them be managed by the GC doesn't work, and we need a solution for that. Most classes work just fine with a garbage collector though.

And if we have classes that are inherently ref-counted or which are sitting inside of smart-pointers, then they're still reference types like they should be. They just have their lifetime managed in a more deterministic manner for those cases where that's appropriate.

- Jonathan M Davis
October 08, 2015
On Thursday, 8 October 2015 at 12:10:24 UTC, Ola Fosheim Grøstad wrote:
> On Thursday, 8 October 2015 at 11:31:49 UTC, Kagamin wrote:
>> cyclic graph. If you must manually verify the graph and put weak references appropriately - what kind of design in that?
>
> It's a system programming language design... If you plan your model before coding it is rather easy to detect cycles in the model. Make the primary data structure a directed acyclic graph, then add back pointers as weak_ptr for secondary relations.

I've programmed extensively in C++ with smart pointers, and in my experience, circular references are rarely a problem. There are some cases where it's obvious that you have one (e.g. where one object owns another and they need to talk to each other), in which case you either use a normal pointer or a weak reference, depending on which makes more sense. And in the cases that you don't catch, you find them in testing, figure out what should be a weak reference to get rid of the circular dependency, you fix it, and you move on. It really isn't a big deal in general, though I suppose that there could be certain ways of designing programs where it would be more problematic.

One advantage of using smart pointers with a GC is that the GC can then clean up circular references, and you don't necessarily even need weak pointers (though there are bound to be cases where they'd still be desirable). But the GC isn't required to solve the problem. It just makes it so that if you do end up with a circular reference problem, it'll fix itself.

- Jonathan M Davis
October 08, 2015
On Thursday, 8 October 2015 at 14:13:30 UTC, Jonathan M Davis wrote:
> One advantage of using smart pointers with a GC is that the GC can then clean up circular references, and you don't necessarily even need weak pointers (though there are bound to be cases where they'd still be desirable). But the GC isn't required to solve the problem. It just makes it so that if you do end up with a circular reference problem, it'll fix itself.

Yes, in general ownership should not be circular at all. It should be a DAG growing from the current actor/process/stack in an unbroken chain of ownership-references.

This should not be conflated with references on the GC heap. In a pure object oriented GC world objects are created and never cease to exist, but when they are no longer reachable the computer can recycle the technical address (but not the conceptual identity). Conceptually automatic garbage collection (like mark/sweep) can be viewed as a memory optimization for our non-ideal computers that would not be needed on a turing machine where you have an endless amount of memory.

So I don't think there are _good_ reasons to call finalizers/destructors on the GC heap, it's a sign of a bad model where the responsibilities are unclear. GC objects should only "own" memory on the GC heap.

Example:

An initial GC file object should just represent the resource identity (URI/filepath), and the open/close actions should be handled by ownership tracking references rooted in the actors/processes that actually are responsible for accessing it.

I think the viewpoint that ownership is rooted in actors and not in objects is a better and more performant view than the "finalizer" view. However if the system allows actors to become unreachable the runtime might need a collection cycle for the actors themselves...

October 08, 2015
On Wednesday, 7 October 2015 at 15:30:17 UTC, Jonathan M Davis wrote:
> On Wednesday, 7 October 2015 at 12:59:05 UTC, bitwise wrote:
>> On Wednesday, 7 October 2015 at 09:49:27 UTC, Marc Schütz wrote:
>>> RefCounted isn't implemented for classes, but there's no reason why it shouldn't work.
>>>
>>>
>>> Really, I don't get why everyone wants to have builtin refcounting, when all that's required is a working way to make escape-proof references.
>>
>> If you make a class that owns a resources that needs deterministic destruction, there is no guarantee that everyone will wrap that class in a RefCounted properly. Also, I've already stated many more problems with struct wrappers.
>
> Except it doesn't even matter if they always wrap it properly - or even if something like DIP 74 is implemented. The core problem is that no object (be it struct or class) which needs deterministic destruction can have its lifetime managed by the GC - be it be simply being directly allocated by the GC or by sitting inside of an object that was put on the GC heap without any kind of ref-counting.

With DIP74, the ref counting is hard coded into the type itself. The intention of the original author of the class is inseparable from the code. The same is not true for a class that is simply "meant" to be used in a context where it has deterministic destruction.

So if I was a graphics programmer, and awake of this issue(deterministic destruction), I could open up a class and just look for opRelease() rather than having to try and reason about it's usage.


> The programmer is always going to have to be careful about where they put an object that needs deterministic destruction.

Again, it's much easier to be careful about this when the author's intent is baked into the class.


> Regardless of the ref-counting mechanism though, you can't guarantee that it's going to be used correctly. The best that we can do is guarantee that if it is used correctly, then the object will be destroyed deterministically.

Since you're probably going to make me repeat myself anyways, I might as well get it out of the way ;)

Again, it's much easier to be careful about this when the author's intent is baked into the class.

     Bit



October 08, 2015
On Thursday, 8 October 2015 at 10:05:53 UTC, Kagamin wrote:
> On Wednesday, 7 October 2015 at 00:17:37 UTC, bitwise wrote:
>> If it takes long enough that C++ has reflection, modules, ranges, stackless coroutines, concepts, etc, then I gotta be honest, I'm gonna start worrying about investing too much time in D.
>
> You manage resources with reference counting in C++? How it deals with circular references?

Resources don't generally own each other, so this isn't really an issue. I had code which would request a resources from a shared store, and then the shared store would keep a weak-pointer to the resource and give out shared pointers to whoever asked. When no one was using the resource anymore, it would be freed automatically.

    Bit

October 08, 2015
On Thursday, 8 October 2015 at 15:51:44 UTC, Ola Fosheim Grøstad wrote:
> So I don't think there are _good_ reasons to call finalizers/destructors on the GC heap, it's a sign of a bad model where the responsibilities are unclear. GC objects should only "own" memory on the GC heap.

As far as I can tell, finalizers are for when you either really don't care when a non-GC resource gets cleaned up (which is probably a bad design in any program that isn't fairly small) or for cleaning up after you screw-up and you forget to call the appropriate function on the object to tell it to free those resources (be it call dispose or something else). In general, finalizers are a sign of a problem. If all you have is the GC heap, or if you need to be able to put an object that needs to clean-up a non-GC resource inside of an object on the GC heap, then you're kind of stuck, in which case, you do manual resource cleanup and have a finalizer as backup, but it's definitely a bandaid rather than an ideal solution. The potential need for finalizers is definitely a con to dealing with a GC.

- Jonathan M Davis
October 08, 2015
On Thursday, 8 October 2015 at 15:59:23 UTC, bitwise wrote:
> Again, it's much easier to be careful about this when the author's intent is baked into the class.

That may be, but my point was that it doesn't actually guarantee that the object is going to be destroyed determinstically. That's going to require that the programmer using the object know that it's designed to be destroyed deterministically and program accordingly. Having it be easier for the programmer to figure out whether an object was designed that way is definitely a plus, but it doesn't make it so that they don't have to worry about it.

- Jonathan M Davis
October 08, 2015
On Thursday, 8 October 2015 at 14:05:07 UTC, Jonathan M Davis wrote:
>
> Maybe, but having classes be value generally makes no sense, because you can't use polymorphism with value types.

This is a huge generalization, and is incorrect. You can still use inheritance.

> Classes are inherently reference types given their semantics.

Incorrect.

> Even in C++ that's the case. It's just that they don't separate out classes and structs the way we do. But classes that use inheritance have to be used as reference types or all you're doing is sharing implementation (which can be done easily enough without inheritance).

It _can_ be done, but that doesn't mean that it's _always_ the best, or even preferred approach.

     Bit