Open KirillAldashkin opened 1 year ago
Just my thoughts:
1) struct
is definitely a must-have feature, but all boxing casts (to object
/interface
) should be done explicilty (#68)
2) unsafe
block is redundant, unsafe
modifier for methods/types is ok
3) C-style pointer manipulation syntax is awkward (*
and &
are used in arifmetic so some keywords instead will be better).
Something like struct Ptr<T>
should be introduced in core library to be used as a pointer type in Draco. This will unite pointers with rest of type system (in C# pointers are not object
).
No ideas about ref
s since I don't know their internal implementation very well, but something like ref struct Ref<T>
to wrap them into a complete type is wanted too (but there's a problem)
4) Some analog of struct Ptr<T>
from above is also wanted to unite function pointers with rest of type system, but there is a problem too
5) Good as is, but should use Span<T>
instead of a pointer and not be unsafe
6) Good as is, but should return Span<T>
by default
So im going to comment only on the points i know something about:
Pointer<T>
I vote for annotation with attribute for structs.
Something like struct Ptr
should be introduced in core library to be used as a pointer type in Draco. This will unite pointers with rest of type system (in C# pointers are not object).
To consider: that's similar to how F# does it, but it may be worth a look
but something like ref struct Ref
is wanted too
I say a type annotation as well, like [Struct]
and [RefStruct]
(could also go with [StackOnlyStruct]
).
Thanks for your input! I generally agree with your points - and admittedly, haven't really thought too deeply on some of them. I definitely like the "leaving the C-heritage syntax behind" mentality,
but something like ref struct Ref is wanted too
I say a type annotation as well, like
[Struct]
and[RefStruct]
(could also go with[StackOnlyStruct]
).
Didn't talk about ref struct
definition syntax here. I meant to introduce the type Ref<T>
for wrapping ref T
in the same way as Ptr<T>
wraps T*
. But, as I said earlier, there is a problem with this.
ref lambdas
?ref func(a: int32) = a * a
is a ref lambda
which type is:
unsafe ref struct RefFunc<TArg, TRet> // some kind of "Func<TArg, TRet>" delegate type
{
private void* _context;
private delegate* managed<void*, TArg, TRet> _function;
public TRet Call(TArg arg) => _function(_context, arg);
public RefFunc(void* context, delegate* managed<void*, TArg, TRet> function)
{
_context = context;
_function = function;
}
}
If ref lambda
captures some context, then it have the same ref safety rules as scoped ref
, otherwise as unscoped ref
func foo(bar: ref (int32) -> unit): unit {
bar(1)
bar(2)
}
func main(): unit {
var counter: int32 = 1
var baz = ref func(add: int32): unit { counter += add; }
foo(baz)
Console.WriteLine(counter)
}
compiles to
static unit foo(RefFunc<int, unit> bar)
{
bar.Call(1);
bar.Call(2);
return unit();
}
[CompilerGenerated]
ref struct _Context
{
public int counter;
}
[CompilerGenerated]
unsafe static unit _lambda(void* context, int add)
{
((_Context*)context)->counter += add;
return unit();
}
unsafe static unit main()
{
_Context context = new() { counter = 1 };
RefFunc<int, unit> baz = new(&context, &_lambda);
foo(baz);
Console.WriteLine(context.counter);
return unit();
}
[CompilerGenerated]
static void _true_main() => main(); // method that returns neither "void" nor "int" can't be an entrypoint
1) ref lambdas
are fast and allocation-free at instantiating.
2) Capturing context in ref lambdas
is also allocation-free, since they can safely access the stack of the method in which they are declared.
1) ref lambda
s can't go on heap, so they can't be used in async
code
2) ref lambda
s with context can't go outside of the method they are declared in
1) C# is known to have a quite good combination of low-level performance features and a high-level OOP model 2) Writing the Draco's core library will require some features that will be unsuitable for regular code
This will be a discussion of including (or not) perfomance-related, low-level and unsafe C# features such as: 1)
struct
s 2)unsafe
context in general 3) Data pointers (*T
) andref
s 4) Function pointers (delegate*<>
) 5) Fixed buffers 6)stackalloc