BuckeyeSoftware / rex

rex engine and game
MIT License
15 stars 0 forks source link

Lamination: Don't allow errors to occur in constructors of any class. #42

Open graphitemaster opened 4 years ago

graphitemaster commented 4 years ago

Move to a Result<T> system of static methods on types like String and Vector which can fail when allocating memory such that the constructor cannot fail. That means copies like the following:

String foo = "something that can fail";

Will no longer compile and instead you'll have to write:

Result<String> foo = "something that can fail";

Which will be enabled by Result<T> calling a special init_from_result static method.

Similarly, constructors like

Vector<Byte> data{1024};

Will no longer work, instead you'll write something like:

auto data = Vector<Byte>::create_with_size(1024);

Which gives a Result<Vector<Byte>> data

And likewise, copy constructors will call special copy_from_result static methods, so

Result<String> a = "hello world";
String b = move(*a);
String c = b; // error
Result<String> d = b; // works

The Result<T> type is special in that it will allow anything returning Result<T> to return an Error type which is just a wrapped String indicating the resulting error.

graphitemaster commented 4 years ago

The Error type then enables a very simple error reporting as return Error{"message"} from functions, like Optional almost. It's encouraged you don't store Result<T> in classes since they're effectively tagged unions with a wasted status flag, they're meant as intermediaries. You can "pull" the value out of one with a simple move(*value). Result<T> will also behave monadic, so you can do things like thing.value_or(substitute_value)

DethRaid commented 4 years ago

I like Result in general. I've started using a similar pattern for many of my classes and it's dope

graphitemaster commented 3 years ago

So instead of a Result type I opted to just use Optional because the only possible error for all the existing types during construction is OOM. Nearly all types have been converted to a static Optional<T> T::create function to create a T with the notable exception of Vector, String, Map and Set which are more involved.

graphitemaster commented 3 years ago

Vector, Map, and Set no longer can fail in constructors, nor do they have copy constructors or copy assignment now. The only types left to fix are String and Function. Some cleanups are necessary in a few other places.

graphitemaster commented 3 years ago

Function has been converted in 51a5ae2 still have String to do and upon further inspection Thread, ThreadPool, and a few other minor types still can fail too, but those are much lower priority than these more regularly used common types. String is going to be the most annoying to deal with.

graphitemaster commented 3 years ago

File and Directory were changed over in eaca0d9 and 0fd8a17 respectively, now only three types can fail in their constructors by the looks of it:

The first two shouldn't be too difficult to do, String is going to be quite involved. Especially WideString for Windows and all the formatting cases.

graphitemaster commented 3 years ago

Thread reworked in 5e9f857. Only ThreadPool and String remain as types that can fail in their constructors.

graphitemaster commented 3 years ago

The Library::Loader type actually could fail in it's constructor too. This was changed in 38ddf63 where it's no longer the case and now uses option types like the rest. ThreadPool and String (WideString too) still remain.

graphitemaster commented 3 years ago

ThreadPool reworked in 30f66bf and String partially reworked in 6575ad3. WideString and String still have copy constructors and assignment operators that can fail, this is just a preliminary change towards completing this issue.

graphitemaster commented 3 years ago

String was reworked in 96609fb now only the copy constructor remains.