Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Struct destructors, "Stack-base Destructor" #1819

Open
Neo-Ciber94 opened this issue Aug 28, 2018 · 2 comments

Comments

Projects
None yet
3 participants
@Neo-Ciber94
Copy link

commented Aug 28, 2018

Struct destructors, "Stack-base Destructor"

For provide a deterministic way for releasing resource one of the "missing features" of C# are the struct destructors to allow structs to release resources when a local variable/parameter go out scope, for this I want to introduce what I call StackDestructor what is just a stack that store function pointers for each instance declared to that local variable, this also can be applied to parameters.

Those StackDestructor are generated from behind by the compiler and are only created for ValueType local variables and parameter; when the variable go out scope all the function pointers are called ensuring that all the instances are cleaned-up.

This destructor like C++ destructors should clean all the ValueType fields calling its respetive destructors.

Here a some pseudo-code to explain the basics of proposal better, where I think is needed a lot of magic:

class valuetype_local_variable<T>
{
	void* _value;
	char* _variableName;
	Stack _stackDestructor;
	
	public valuetype_local_variable(char* variableName, T& someInstance)
	{
		_variableName = variableName;
		_value = &someInstance;
		_stackDestructor = new Stack(1);
		
		_stackDestructor.Push(someInstance.GetInstanceDestructorFunctionPointer());
	}
	
	event OnOutScope()
	{
		while(!_stackDestructor.IsEmpty)
		{
			funcPointer ptr = _stackDestructor.Pop();
			ptr();
		}
    ]
};
unsafe public struct Allocator
{
	private void* buffer;
	private uint byteLength;
	
	public ref byte this[uint offset];
	
	Allocator(uint bytes){ /*Allocation*/ }	
	~Allocator(){ /*Deallocation*/ }
}

For this way there is not needed to make a changes in the sintax and just declare a destructor on the struct just like classes or C++.

{
	Allocator allocator1 = new Allocator(100u);
	Allocator allocator2;
	
} // Destructors of allocator1 and allocator2 local variables called here.
{
	Allocator allocator1 = new Allocator(100u); //Here the 'StackAllocator' of the 'allocator1 local_variable' store a pointer to the new instance destrutor method.
	allocator1 = default; //Here other function pointer is store to the new instance destructor.
} //Each of the pointers stored in the StackAllocator of the 'allocator1 local variable' are called here.

Ok, but what happen during the struct copy? In those cases the new local variable store the function pointers but is marked as a copy so its destructors are not called.

{
	Allocator allocator1 = new Allocator(100u); //A new function pointer is added to the StackAllocator of the 'allocator1 local_variable'.
	Allocator allocator2 = allocator1; //A copy is made, destructors function pointers from allocator1 are copied to allocator2.
} //All the destructors of the 'local_variable allocator1 StackAllocator' are called here as well for allocator2 but is not called because is a copy.

The same behaviour happens when are passed as parameters.

{
	Allocator allocator1 = new Allocator(100u);
	WriteBytes(allocator1);
	
} //allocator1 destructors are called here.

Also can be introduced an new attribute DestroyAttribute, that indicates that the destructor of the value passed should be called.

public static ReadBytes([Destroy] Allocator allocator)
{
} //Destructor is called here whether is a copy or not.
public static ReadBytes(Allocator allocator)
{
	
} //allocator destructors not called because is a copy.

But when are passed by ref or in are destroyed within the method.

{
	Allocator allocator1 = new Allocator(100u);
	WriteBytes(ref allocator1);
	
} //allocator1 have not destructors to call at this point.
public static ReadBytes(ref Allocator allocator)
{
	
} //allocator destructors called here.

But what if the instance is not store in a local variable? In this case the instance is passed and destroyed within the method.

{
	WriteBytes(new Allocator(100u));	
}
  • What happen to ValueType types that don't declare a destructor? The compiler should provide a defualt destructor for the type but is also marked with an attribute (for example: DontDestroyAttribute) to indicates that function pointers of that type should not be store.

Maybe a really risky proposal that involves a lot to change/add, thoughts?


RELATED PROPOSALS:


Remember, use csharp to insert C# code but remember, "a great power carries a great responsibility" .

@HaloFour

This comment has been minimized.

Copy link
Contributor

commented Aug 28, 2018

#1623

That would enable you to use using with ref structs

@ufcpp

This comment has been minimized.

Copy link

commented Aug 28, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.