November 18, 2021

On Thursday, 18 November 2021 at 13:38:58 UTC, Atila Neves wrote:

>

On Wednesday, 17 November 2021 at 21:59:51 UTC, Ola Fosheim Grøstad wrote:

>

On Wednesday, 17 November 2021 at 21:46:45 UTC, Atila Neves wrote:

>

The GC isn't going anywhere. It's the easiest way to write memory-safe code other than leaking everything.

What is the plan for destructors?

Objects with destructors should not be allocated on the GC-heap. Will this become a type error that is caught at compile time?

No plans right now. Refresh my memory: what are the main issues?

Off the top of my head:

  1. The main issue is that beyond the trivial examples destruction order matters and you need to keep objects alive to get the correct cleanup of resources. Think database/transaction, GPU/texture, etc. So if you assume RAII for aggregates, then aggregates written for those won't work with GC. Though you could support both by adding finalizer handlers, then you could deny GC allocation of objects with destructor and no finalizer handler. (just one possibility)

  2. Performance of GC collection will be faster if you have no destructors. Especially if you move to local GC heap (per actor). Then you can just release the whole heap and do no scanning when the actor is done. If the average actor's lifespan is short and you have plenty of memory, the GC overhead will drop from "O(N)" to "O(1)" (average).

Might be other issues.

November 18, 2021

On Thursday, 18 November 2021 at 13:56:00 UTC, Atila Neves wrote:

>

And those feature would be...?

I personally would like to see C++ compatible exceptions, lambdas, and coroutines (and build a D actor on top of that), but I am not saying it is critical or important. Those are just my personal instincts. Others might have other preferences that might be equally valid.

I haven't thought a lot about the consequences, as I don't think it will happen anytime soon.

November 18, 2021
On Thursday, 18 November 2021 at 06:25:29 UTC, rumbu wrote:
> Lol. Look, C# is not a garbage collected language:
>
> int* x = stackalloc int[100];
> int* y = Marshal.AllocHGlobal(1000);
> struct RC<T> where T: struct { ... }
>
> O course, metaprogramming makes things easier in D, but pretending that D is not a garbage collected language when you cannot join two arrays or throw an exception without digging  outside the language for a replacement is absurd.

@nogc unittest
{
	import std.container.array;
	auto a = Array!int(1, 2);
	auto b = Array!int(3, 4);
	a ~= b;
	import std.algorithm;
	assert(a[].equal([1,2,3,4]));

	static const ex = new Exception("hi");
	throw ex;
}

November 18, 2021

On Thursday, 18 November 2021 at 14:12:36 UTC, Ola Fosheim Grøstad wrote:

>

On Thursday, 18 November 2021 at 13:56:00 UTC, Atila Neves wrote:

>

And those feature would be...?

I personally would like to see C++ compatible exceptions, lambdas, and coroutines (and build a D actor on top of that), but I am not saying it is critical or important. Those are just my personal instincts. Others might have other preferences that might be equally valid.

I haven't thought a lot about the consequences, as I don't think it will happen anytime soon.

I don't know if C++ compatibility is a good direction. Most modern languages try to distance themselves from C/C++ and only offer C ABI interop for legacy software and popular libraries. D always felt like trying to start from a clean slate and minimize the dependencies on C/C++. By adding C++ compatibility, whether we like it or not we will also inherit negative things that are related with C++. D should stand on its own as a language, rather than be a GC sidekick to make code that works with C++.

(ironically, languages which don't care about c++ interop at all seem to have better bindings work with popular C++ projects such as Qt or Bullet).

November 18, 2021

On Thursday, 18 November 2021 at 13:37:28 UTC, Atila Neves wrote:

>

On Thursday, 18 November 2021 at 04:24:56 UTC, rumbu wrote:

> >
  • wrong idea of what private means (yes, I know that you disagree on that, but every OOP book/study/reference considers the class as unit of encapsulation);

As you've mentioned, we're not going to agree. I don't think this is failing to evolve either since it's by design.

Let's agree to disagree. For me, it's a failure.

> >
  • struct inheritance

Inheritance (subtyping) and value types don't mix.

A struct can inherit 2 things:

  • another struct
  • an interface

This doesn't involve boxing for structs, just the compiler generating a templated function when encounters the interface as a parametter. At least this is how it is done in BeefLang.

interface I { void foo(); }

void bar(I i)
{
   i: foo;
}

class C: I { void foo() {} }
struct S: I { void foo() {} }

C c = new C();
S s = new S();

void callMe(I i) { i.foo }

callMe(c); // compiler will call callMe as usual
callMe(s); // compiler will generate and call a specialized callMe(S i)

>

Could you please explain what these mean?

>

explicit interface implementations

interface I1 { void foo(); }
interface I2 { void foo(); }

class C : I1, I2
{
    void foo() { writeln ("I am I1's and I silently hide I2's foo"); }
    void I1.foo() {writeln("I am I1's foo"); } //this doesn't work
    void I2.foo() {writeln("I am I2's foo"); } //this doesn't work
}

> >

class destructuring

I already explain it, controlled decomposing of classes or structs;


//if tuple syntax was built-in (item1, item2, ....)
struct Coordinate
{
   int x, y, z;
   void opDeconstruct(out x, out y) { return (x, y) }
   void opDeconstruct(out x, out y) { return (x, y, z) }
}

Coordinate co;

(x,y) = co;
(x,y,z) = co;

> >
  • properties

What's missing?

A better syntax? Compiler generated backing fields? The fact they are not working as advertised?

class C
{
    int _fld;
    int prop() {return _fld;}
    void prop(int x) { _fld = x; }
}

C c = new C();
c.prop += 42;  ///oops!
> >
  • pattern matching on class type

AFAIC this is an anti-pattern. IMHO, in OOP, there should be a switch exactly in one place in the program, and that's where instances get created. I don't know why anyone would want to recreate the functionality of the virtual table in an ad-hoc way.

Multiple dispatch blurs this, however.

>
  • pattern matching on fields/properties

How would this work?

switch (JSONValue)
{
   case JSONNumber n: writeln ("I have a number %s", n);
   case JSONString s when s.Length > 100 : writeln("long string");
   case JSONString s: writeln("short string");
}

November 18, 2021

On Thursday, 18 November 2021 at 14:56:40 UTC, rumbu wrote:

> > >
  • pattern matching on fields/properties

How would this work?

switch (JSONValue)
{
   case JSONNumber n: writeln ("I have a number %s", n);
   case JSONString s when s.Length > 100 : writeln("long string");
   case JSONString s: writeln("short string");
}

Isn't that just std.sumtype/tagged union?

November 18, 2021

On Thursday, 18 November 2021 at 14:54:31 UTC, JN wrote:

>

I don't know if C++ compatibility is a good direction. Most modern languages try to distance themselves from C/C++ and only offer C ABI interop for legacy software and popular libraries. D always felt like trying to start from a clean slate and minimize the dependencies on C/C++. By adding C++ compatibility, whether we like it or not we will also inherit negative things that are related with C++. D should stand on its own as a language, rather than be a GC sidekick to make code that works with C++.

Yes, but then the current C++ interop strategy should be unwound, otherwise you end up in that uncanny-valley situation where you are neither this nor that. You end up with the disadvantages of tracking C++ with limited benefits. Same for importC. You have to go all in to be taken seriously, not just dip your toes.

It is a difficult choice to make.

Coroutines are going to be more common over time in C++ code. Exceptions are less of a burden for libraries in C++ than it used to be.

So, long term strategic planning should say: do it, or pull out completely?

November 18, 2021
On Thursday, 18 November 2021 at 14:31:36 UTC, Nick Treleaven wrote:
> On Thursday, 18 November 2021 at 06:25:29 UTC, rumbu wrote:
>> Lol. Look, C# is not a garbage collected language:
>>
>> int* x = stackalloc int[100];
>> int* y = Marshal.AllocHGlobal(1000);
>> struct RC<T> where T: struct { ... }
>>
>> O course, metaprogramming makes things easier in D, but pretending that D is not a garbage collected language when you cannot join two arrays or throw an exception without digging  outside the language for a replacement is absurd.
>
> @nogc unittest
> {
> 	import std.container.array;
> 	auto a = Array!int(1, 2);
> 	auto b = Array!int(3, 4);
> 	a ~= b;
> 	import std.algorithm;
> 	assert(a[].equal([1,2,3,4]));
>
> 	static const ex = new Exception("hi");
> 	throw ex;
> }

As I said, you are digging outside the language spec with Array and equal and with the overloaded operators opOpAssign and opSlice, even they are not obvious.

Preallocating global exceptions with standard messages is not a good idea.


November 18, 2021

On Thursday, 18 November 2021 at 15:00:22 UTC, JN wrote:

>

On Thursday, 18 November 2021 at 14:56:40 UTC, rumbu wrote:

> > >
  • pattern matching on fields/properties

How would this work?

switch (JSONValue)
{
   case JSONNumber n: writeln ("I have a number %s", n);
   case JSONString s when s.Length > 100 : writeln("long string");
   case JSONString s: writeln("short string");
}

Isn't that just std.sumtype/tagged union?

Yes, it is, but the question was about oop evolution in D and keeping the pace with other languages, not about "here you have another lib for this".

November 18, 2021
On Thu, Nov 18, 2021 at 03:19:39PM +0000, Rumbu via Digitalmars-d wrote:
> On Thursday, 18 November 2021 at 15:00:22 UTC, JN wrote:
> > On Thursday, 18 November 2021 at 14:56:40 UTC, rumbu wrote:
> > > > > * pattern matching on fields/properties
> > > > 
> > > > How would this work?
> > > 
> > > 
> > > ```d
> > > switch (JSONValue)
> > > {
> > >    case JSONNumber n: writeln ("I have a number %s", n);
> > >    case JSONString s when s.Length > 100 : writeln("long string");
> > >    case JSONString s: writeln("short string");
> > > }
> > > 
> > > ```
> > 
> > Isn't that just std.sumtype/tagged union?
> 
> Yes, it is, but the question was about oop evolution in D and keeping the pace with other languages, not about "here you have another lib for this".
[...]

IMO, this is actually a strength of D: it is powerful enough to express these constructs as library code instead of being baked into the language.

Of course, the library experience definitely can be improved -- I don't argue with that.  Some language changes to make library solutions more powerful would definitely be welcome.  Documentation needs improvement, and ecosystem definitely needs work.  But I don't see library solutions as a failure; I see it rather as a success that libraries are able to express such things, whereas in languages like Java the language doesn't let you express them, so you have no choice except to bake it into the language.


T

-- 
Stop staring at me like that! It's offens... no, you'll hurt your eyes!