March 16, 2019
On Saturday, 16 March 2019 at 20:17:50 UTC, Jacob Carlborg wrote:
> Instead of having a function allocate memory, pass a buffer, delegate, output range or something similar to the function. Then whatever you pass can decide if it should allocate using the GC, malloc or something else.

It would have to be a delegate or an output range, because in most cases the callee wouldn't know in advance how much storage it needs to allocate.

Anyway, it would be pretty nice if there were a standardized way to tell a function how it should allocate its memory; it would allow some nice strategies like "I know that I'm going to discard most of what this function allocates, so just put in in a continuous buffer; then deep-copy the relevant data to GC memory, and throw the rest away" (eg in a parser).

However, for that to work, you'd probably need a way to pass implicit arguments to a function without having to specify `foobar(defaultGcAllocator, x, y, z)` every time you call a function.
March 16, 2019
On 3/16/19 5:17 PM, Olivier FAURE wrote:
> Anyway, it would be pretty nice if there were a standardized way to tell a function how it should allocate its memory; it would allow some nice strategies like "I know that I'm going to discard most of what this function allocates, so just put in in a continuous buffer; then deep-copy the relevant data to GC memory, and throw the rest away" (eg in a parser).

Wow, that is a really fascinating idea ...

March 17, 2019
On 17/03/2019 10:17 AM, Olivier FAURE wrote:
> 
> Anyway, it would be pretty nice if there were a standardized way to tell a function how it should allocate its memory; it would allow some nice strategies like "I know that I'm going to discard most of what this function allocates, so just put in in a continuous buffer; then deep-copy the relevant data to GC memory, and throw the rest away" (eg in a parser).

I have questions related to how much garbage this parser is creating.

Ignoring how complex of an idea this actually is, we would need clear set of examples demonstrating that this cannot be done manually (choosing between GC and another allocator).

But otherwise, neat.
March 17, 2019
On 2019-03-16 22:17, Olivier FAURE wrote:

> However, for that to work, you'd probably need a way to pass implicit arguments to a function without having to specify `foobar(defaultGcAllocator, x, y, z)` every time you call a function.

With my idea that would be the second layer, sitting on top of the more general layer.

I guess a parameter with a default value could work:

void foobar(Allocator)(int x, int y, int z, Allocator allocator = defaultGcAllocator);

-- 
/Jacob Carlborg
March 17, 2019
On 2019-03-15 00:06, H. S. Teoh wrote:

> OTOH, though, these twists and turns in the development of the language
> are also an integral part of what it is; UFCS, for example, came about
> from a clever hack added in order to make built-in arrays compatible
> with the then newly-introduced range API. Later on, people clamored for
> this "hack" to be extended to other types and become officially
> accepted. It was a huge success IMO. Nowadays, I can't imagine writing D
> code without UFCS.

That's not what happened. UFCS for arrays existed in D1, long before D2 and when ranges were introduced.

-- 
/Jacob Carlborg
March 17, 2019
On Sun, Mar 17, 2019 at 10:50:15AM +0100, Jacob Carlborg via Digitalmars-d wrote:
> On 2019-03-15 00:06, H. S. Teoh wrote:
> 
> > OTOH, though, these twists and turns in the development of the language are also an integral part of what it is; UFCS, for example, came about from a clever hack added in order to make built-in arrays compatible with the then newly-introduced range API. Later on, people clamored for this "hack" to be extended to other types and become officially accepted. It was a huge success IMO. Nowadays, I can't imagine writing D code without UFCS.
> 
> That's not what happened. UFCS for arrays existed in D1, long before D2 and when ranges were introduced.
[...]

Wasn't that a parser quirk or something that was later taken advantage of?


T

-- 
It always amuses me that Windows has a Safe Mode during bootup. Does that mean that Windows is normally unsafe?
March 17, 2019
Am Sat, 16 Mar 2019 21:17:02 +0000 schrieb Olivier FAURE:
> 
> However, for that to work, you'd probably need a way to pass implicit arguments to a function without having to specify `foobar(defaultGcAllocator, x, y, z)` every time you call a function.

You can implement that using TLS globals, I think this is what std.experimental.allocators theAllocator is supposed to do. Of course you're limited in typing, you can't use templates there.

-- 
Johannes
March 17, 2019
On Thursday, 14 March 2019 at 21:32:21 UTC, JN wrote:
> On Thursday, 14 March 2019 at 10:02:20 UTC, Paolo Invernizzi wrote:
>> [...]
>
> To be frank, even though I'd love the idea of D3, I don't think it's just a matter of Phobos. Phobos is a victim of the underlying ideology of D, which is both it's blessing and a curse. That ideology is the idea that all paradigms are equal and every usecase should be supported. In languages like Java/C#, if someone asks how to do manual memory management, the answer is either "you can't" or "interop with C". In D, the answer is "oh, you can totally do that, just this won't work, and this is needed, and this will probably not compile, oh and no one tested that". It adds a lot of cognitive overhead, and unfortunately there are many points of division like that. @nogc/RC, GC, add to that -betterC too. Which one would a "new" Phobos support? I don't think you can support them all. You'd have to go for the lowest common denominator, which is @nogc, but if stdlib doesn't require a GC, what is the point of a GC at all. Especially since GC is an issue when porting D to Webassembly (need to use -betterC for that right now). I think if D3 was to be successful, it'd have to be a bit more opinionated. I don't mean the language has to become a OOP behemoth (I'd love that though haha) or a functional monadic transformer combinator, but it'd be nice to better define a scope of the language and be able to answer a question "Can D do XYZ?" with "No, it's not useful and you shouldn't do it this way".
>
> Also, some language features seem dubious or hardly used at all. Does anyone really use contracts? I know they're sweet and Eiffel and everything, but does anyone ACTUALLY use them and doesn't stick to good old asserts? Perhaps rather than implementing (and supporting! each feature has to work well with other features which adds support overhead) such features, it'd be more useful to add features like struct initialization outside of assginments, which feels to me like a much nicer improvement to the language.

There are a lot of changes, with large consensus, that are currently not admitted because of existing code.

Just **today** another one coming from Walter [1]:

"As mentioned earlier, scope guard will catch Errors, but it should really only catch Exceptions. This hasn't been fixed because there's existing code that relies on it catching Errors."

And the history of D is full of such examples, low hanging fruits, actionable.

/ Paolo


[1] https://forum.dlang.org/post/mailman.7569.1552776840.29801.digitalmars-d-bugs@puremagic.com

March 17, 2019
On Saturday, 16 March 2019 at 21:17:02 UTC, Olivier FAURE wrote:
> On Saturday, 16 March 2019 at 20:17:50 UTC, Jacob Carlborg wrote:
>> Instead of having a function allocate memory, pass a buffer, delegate, output range or something similar to the function. Then whatever you pass can decide if it should allocate using the GC, malloc or something else.
>
> It would have to be a delegate or an output range, because in most cases the callee wouldn't know in advance how much storage it needs to allocate.
>
> Anyway, it would be pretty nice if there were a standardized way to tell a function how it should allocate its memory; it would allow some nice strategies like "I know that I'm going to discard most of what this function allocates, so just put in in a continuous buffer; then deep-copy the relevant data to GC memory, and throw the rest away" (eg in a parser).
>
> However, for that to work, you'd probably need a way to pass implicit arguments to a function without having to specify `foobar(defaultGcAllocator, x, y, z)` every time you call a function.

How about something like the following?
It introduces an overload of keyword new, a keyword 'old' and a keyword 'lifetime' to pass in an IAllocator as a template argument to a function, and change the name mangling to add it as a hidden parameter.

/*MyClass is an implicit template which takes an IAllocator. It can always be implicitly casted to a MyClass for backwards compatibility. It can use this allocator using the .allocatorOf property.*/

class MyClass
{
  public MyClass getANEwInstance(MyClass a, MyClass b)
  {
    .... //some code


      return this.allocatorOf new MyClass();
  }

/*This function takes Myclass A as a parameter and returns a new instance of MyClass using thesame allocator. if no explicit allocator is used for a, or no allocator is known, the default GC_ALLOCATOR is used. This allows for better compatibility with existing D libraries.*/

  public lifetime(a) getANewInstanceFromParameter(lifetime MyClass a)
  {
    .... //some code
      return a.allocatorof new MyClass();
  }

/* a class which has a lifetime associated with it, should be able to decay into a "normal" class so they can still be used in existing codebases. They are an opt-in feature because of it. simpleProperty() demonstrates this. */

  public bool simpleProperty(MyClass myClass)
  {
    ....
    return myClass.someProperty();
  }
}


//usage:
public void foo(IAllocator A)()
{
  MyClass c1 = new MyClass(); //Use default GC allocator.

  MyClass c2 = Mallocator new MyClass (); // Allocate using malloc.

/*Instantiate MyClas using allocator A, and mangle the allocator A into the
resulting type as the first template parameter.*/
  MyClass c3 = A new MyClass();

/* since a reference to a class instance is still a pointer, we can discard the allocator of the pointer and call regular D, C++ and C functions with it. */
  println(c3.simpleProperty());

  // get a new object with thesame allocator as c1, since c1 is a @lifetime object.
  auto c4 = c1.getANEwInstance();

  auto c5 = c2.getANewInstanceFromParameter(c3);

  old c1; // no-operation
  old c2; // destruct and free c2
  old c3; // destruct and free c3 if A is not a GC allocator using introspection.
  old c4; /*destruct and free using thesame allocator as c1, meaning no-op in this case.*/
  old c5; /*destruct and free using thesame allocator as c3, meaning this is conditional on A being a GC allocator.*/
}
`

I think that this is an example which would be quite easy to learn, not a huge strain on the developers, backwards compatible with existing D code and potentially immensely powerfull. It would also give helpful info which can be used by debuggers and other tooling. One thing it can never do is return an object which was conditionally allocated with one allocator or another.
March 18, 2019
On 2019-03-17 12:27, Johannes Pfau wrote:

> You can implement that using TLS globals, I think this is what
> std.experimental.allocators theAllocator is supposed to do. Of course
> you're limited in typing, you can't use templates there.

Then the functions can't be pure.

-- 
/Jacob Carlborg