Appendix A. My view on language design
Intro
Each time a new language comes out or gets popular there are always things that bother me. The most weird thing I keep stumbling upon is abbreviations and naming conventions that got stuck from old languages.
Keywords & abbreviations
Even when abbreviations are not a thing, the language sometimes has other quirks.
For example JavaScript has a clear keyword for making functions
just
called function
, but in combination with other quirks.
If its not abbreviations, it something else like these keywords:
string
(is never replaced by something liketext
for whatever reason)int
(is only sometimes referred to as anInteger
althoughWholeNumber
would even be better)double
(waitdouble
of what? Double of 1, 10, 100, double portion)float
&decimal
(could also be something likeFloatNumber
&DecimalNumber
)
Testing & result processing
While testing, one of the things I really liked is the is runnable/testable
documentation from rust.
However I don't really like some of its abbreviations like fn
& some other
keywords.
That is not the only thing however as what I don't like is also how
some languages are too focussed on exceptions and panick handlers.
What I prefer however is not to have to deal with 2 ways of returning something.
The Result
pattern is a good way to deal with that, but unfortunately its
not always straigt forward if the language already relies on exceptions.
The exceptions directly lead to my next point & that is how test methods are defined. Currently, the most common way is to write a test method and run one or more asserts at the end that crash if something is wrong. While this works, it not my most favorite design. I may not be able to change how its always has been done in an existing codebase, but I would rather see somthing like this:
namespace UnitTests;
// Yes, this is not valid C# because its expects class here!
// This is not simply a class however so why is it possible to create a record
// type, but a test still has to be annotated with attributes?
Test RotationTest : UnitTest
{
static CharacterBody3D CharacterWith0RotationOnPosition0 => new()
{
RotationDegrees = Vector3.Zero,
Position = Vector3.Zero
};
// Yes, this is not valid C# because its expects override here!
// Another weird quirk, why do I have to override while actually implementing?
// Even the extra `List<TestResultFunction>` might be unnecessary in some
// cases: `implement TestFunctions =>` since the base class already defines
// the type
implement List<TestResultFunction> TestFunctions =>
[
Test(
whether(() => CharacterWith0RotationOnPosition0.RotateY45DegreesTowards(new Vector3(10, 0, 0)))
.matches(character => character.RotationDegrees.Y.ShouldBe(-90))
.because(character => $"character's y rotation ({character.RotationDegrees.Y}) should change to -90 degrees")
.when("target is right of player")
),
Test(
whether(() => CharacterWith0RotationOnPosition0.RotateY45DegreesTowards(new Vector3(10, 0, 5)))
.matches(character => character.RotationDegrees.Y == -90)
.because(character => $"character's y rotation ({character.RotationDegrees.Y}) should turn to -90 degrees")
.when("target is almost right of player")
)
];
}
Domain specific test prototype in Godot
The above is based on a working DSL (domain specific language) for my Godot game. It might also need some tweaking, but its the best I could come up with, without going too crazy with expressions and reflections. This is a work in progress however as I don't know where I am going to stumble upon as I progress further with the tutorial and its related game!