Someone added new exercises to Zig track. I am trying to solve them. But I noticed that I am forced to form bad habits. For example, Robot Simulator exercise currently does now allow to modify the struct in-place and does not allow to return an error.
Current method signature in question is
pub fn move(self: Robot, instructions: []const u8) Robot {
It forces the user to awkwardly copy the struct every time they call the method
robot = robot.move("A");
It is easy to fix by making self a pointer.
pub fn move(self: *Robot, instructions: []const u8) Robot {
Then we could call the method much easier
robot.move("A");
Second issue is bad approach to error handling. I know three ways to handle invalid inputs in Zig: return an error, ignore or assume it was impossible:
if (invalid_input) return error.InvalidInstruction;
if (invalid_input) {};
if (invalid_input) unreachable;
One could argue that you should never ignore invalid inputs and you should not assume anything about user input. This leaves returning an error the only correct way.
But you can not just return an error in Zig. You need error union return type. But changing the return type breaks the tests:
test_robot_simulator.zig:9:37: error: error union type 'error{InvalidInstruction}!robot_simulator.Robot' does not support field access
test_robot_simulator.zig:9:37: note: consider using 'try', 'catch', or 'if'
So most students will form a bad habit of ignoring invalid input.
If we want to fix this we have three options. We can allow returning an error:
pub fn move(self: *Robot, instructions: []const u8) error{InvalidInstruction}!Robot {
We can say in the instructions that invalid input is impossible.
We can say in the instructions that invalid characters in the input should be ignored.
Error handling is a major selling point of Zig. Exercises should encorage learning about error handling.
What do you think?