Thread overview
My solution to the GC problem
Jan 07, 2023
Menshikov
Jan 07, 2023
IGotD-
January 07, 2023
/*
   I came up with an idea last night.
  If the storages (variables, function arguments, structure or class fields) store the type at compile time, why not store the allocator at compile time?

   That is, information about the allocator is stored neither in the type nor in the value, but as an attribute of the store.

   * First, it introduces new interesting idioms ('new void', 'new __stack', for example).
   * Secondly, if possible, it does not generate a bunch of template code and does not take up memory in values
   * Third, it's readable
   * And the fattest plus is that in order to rewrite std and runtime for them,
  you just need to add the new attribute to the function arguments,
  and in half the possible cases, it will work!
   * I haven't seen it, in any language! Allocators are well developed in beeflang, but it does not store the allocator in storage, it is on the shoulders of the user.

   What do you think of it?
*/

/***SYNTAX***/

newAttribute:
  new aliasValue
  new extern aliasValue
  /*only in funcs*/
    new
    new: identifier


//alias aliasValue is either what alias can accept, or reserved allocators (__GC, __stack), or the void keyword



/***VARIABLES***/

/*new*/{
  string text new myAlloc;

  /*
    same as
    scope string text new extern myAlloc; // 'extern' need to don't generate scope(exit) and scope attr
    scope(exit) destroy(text);
  */

  text.length = 90; // ok

  string text2 new myAlloc;
  text2 = text; // error!
  text2 = new string(text); //ok
  text2 = move(text); //ok
}

/*new extern*/{
  string text new extern myAlloc;
  string textGC = text; //error: __GC != myAlloc
  /*
    string textGC new extern __GC;
  */

  string text2 new extern myAlloc;
  text2 = text; // OK!

  text2.length = text2.length + 5;
  assert(text2.ptr != text1.ptr);

  destroy(text2);
  destroy(text1);
}

/***STRUCTS***/

{
  struct Person{
    string name;
    int age;
  }

  Person likesGC;
  Preson hatesGC new myAlloc;

  //pseudocode
  static assert(__traits(isSame, allocof(hatesGC), allocof(hatesGC.name)));
  static assert(__traits(isSame, allocof(likesGC), allocof(likesGC.name)));
}

{
  struct Sample{
    IAllocator alloc;
    string text new alloc; // why not?
  }

  Sample instance;
}


{
  struct Sample{
    void method() {
      string text new allocof(this);
      pragma(msg, allocof(this)); //ERR: __alloc - rt function argument
    }
  }

  Sample sample new myAlloc;
  sample.method();
}

{
  struct Sample{
    void method() new thisAlloc{
      string text new thisAlloc;
      pragma(msg, thisAlloc); //OK
    }
  }

  Sample sample new myAlloc;
  sample.method();
}

/***FUNCTIONS***/

/*
  no additional code is generated, the only thing that happens is type checking
*/

void someAlloc(ref char[] name new){
  name.length = 4;
  name[] = "jack";

  pragma(msg, allocof(name)); // error! unknown in ct
}

void noAlloc(char[] new void){
  assert(name.length == 4);
  name[] = "jack";
}


//'new void' means that the type allacator is not known, and that the methods of this structure that require the structure's allacator cannot be called

void noAllocStruct(Person a new void){
  a.age = 0; //ok
  a.name = "Walter"; ///error: allocation
}

void multiArgs(string a new, string b new);

//something like a label is created and the caller checks the storage allocators
string new a1 multiArgsSameAllocator(string a new: a1, string b new: a1){
  string text new a1;
  pragma(msg, a1);//ERR a1 - AllacatorI
  pragma(msg, typeof(a1));//=> AllacatorI
  return a ~ b;
}

//known allocator at CT
//code generation!

void sample(alias Alloc)(string text new Alloc)
{
  pragma(msg, allocof(text)); //OK
}

//ABI

void fu_one(string a new, int n)
->
void fu_one(string a, int n, IAllocator __a_alloc)

void fu_multi(string a new, string b new, int n)
->
void fu_multi(string a, string b, int n, ushort __a_id, ushort __b_id, IAllocator[] __allocs...)


/***BONUS***/

{
  string dtext;
  char[] ctext new __stack = dtext.toStringz!__stack; //kinda alloca in c library
  ctext ~= "boo"; // error

  ubyte[] result = someCShit(ctext)[0..length];
  //PROFIT, no heap use
}
January 07, 2023
The problem isn't syntax.

Its semantics, lifetime analysis.

Being able to specify memory allocators has long been desired, but getting it actually working... that's the hard part. A large part of it is indirection issues in memory lifetime. Currently not a solved problem for us.
January 07, 2023

On Saturday, 7 January 2023 at 00:18:31 UTC, Menshikov wrote:

>

string text2 new myAlloc;
text2 = text; // error!
text2 = new string(text); //ok
text2 = move(text); //ok

Ideas how to get of the dlang GC jail is always welcome. One question is how is the type information going to be stored when you use "string text2 new myAlloc" for example. What is the type of 'text2'? Since you want to prevent assignment of a type that is allocated differently that information must be stored somehow.

BTW. Beef language looks interesting, haven't paid attention to it previously. Worth checking out.