After a few months of break, over the last week or so I finally had some time to work on my pet programming language #Rocket again.

My main goal was to fix a bug that prevented some built-in types (ints, booleans, ...) from being used as instances of a protocol (as in #Python - think interfaces in #Java, traits in #Rust or ...). The reason was that for these types I didn't have any runtime type info. If they were stored in a variable (or function parameter) of type `MyProtocol` that was that - there was no more information on the type except just that: It implements the protocol `MyProtocol`. No way of knowing the actual type or finding the implementation of the methods required by the protocol.

So I had to refactor how ints and booleans were represented internally. As you can imagine, that's a change quite deep in the language. It affected arrays (which store their length - an integer), strings (which under the hood ultimately are arrays of integers) and some other stuff. Changing the representation of booleans required adjustments in parts of the language that deal with booleans: lazily evaluating logical `and`s and `or`s, `if` statements, `while` loops, etc.

Anyway, after the refactoring I think the code is a bit cleaner. And once I had this, fixing the bug was literally a two line change (plus imports and tests).

Also found and fixed another bug: When importing two submodules of the same top-level module (e.g. `import mymodule.submodule_1; import mymodule.submodule_2`) the second import statement used to fail because the name `mymodule` already existed (was already taken) in the code doing the imports (it was created by the first import statement).

And then there was a third bug I introduced in the refactoring of the representation of ints. It lead to `-some_unsigned_int` to be treated as another unsigned int (rather than a signed one) in some regards. My test case converting `-9223372036854775808` (the minimum value a signed 64 bit integer can hold) to a string caught it.

On a side node: I'm so grateful I started writing lots of test cases for this project. The amount of bugs they've caught that would have gone unnoticed otherwise is worth a million. Always write test cases if you care about your software.

#RocketLang

Today I committed and pushed my code implementing "for" loops for my pet #programminglanguage, #rocket.

So, if an object has an `__iter__` method and the object returned by that has a `__next__` method, you can now write:
```
for x in my_object:
...
```

So far I haven't implemented the `else` branch (that's supported by #Python), because I'm not sure how useful/common that actually is.
Also, so far the syntax is limited to a single variable, unpacking something (e.g. `for i, x in enumerate(my_object)`) is not yet supported.

I feel like half of the effort/code went into handling the new variable `x`. It can optionally be declared with a type (e.g. `for x: int64 in my_object`), in which case it will be treated as a *new* variable (that exists only inside the loop). If you *omit* the type, it imitates the behaviour of an assignment statement (i.e. `x = ...`).
In that case, it either
- uses an existing variable or
- creates a new variable or
- throws a `TypeError`.

While writing test-cases I also discovered a bug elsewhere in my code:
Two of my new test cases (for the for loops) check that the for loop can work with `__iter__` and `__next__` methods of a different type. E.g. if you have a type `A`, type `B` inherits from type `A`, and the `__iter__` method was declared with a parameter of type `A` (rather than `B`), you should still be able to write `for x in B(): ...`, because the object of `B` is also an instance of `A`, so you should be able to call `__iter__` with a parameter of type `B`, too.
(As another example, `__iter__()` could have an optional, second parameter, and it should still work in a for loop.)

Anyway. While writing these test cases, I discovered the bug that (currently) you cannot actually declare a variable with a fixed type if that type is a `protocol`. The reason is that so far my code assumed that every type has a *default value*. (E.g.: the default value of ints is 0, the default value of boolean is `False`.) However, that doesn't make sense for *protocols*, since
a) there's no guarantee there is a type implementing the protocol when the variable is created (there's not even a guarantee there will ever be a type implementing the protocol) and
b) even if there where many types implementing the protocol, it wouldn't make sense to arbitrarily choose one of them and initialise the variable with the default value of that type. That would be completely random guesswork.

I guess I'll have to drop the assumption that every type has a default value, but...
That was a nice assumption, because it made life *so much* easier.
Consider for example creating an array of type `T`. If `T` has a default value, there's no issue, you just allocate the array and initialise all the items in the array with the default value, then let the programmer do with it as (s)he pleases. There is no risk the programmer might use uninitialised memory. If `T` does *not* have a default value... You'd have to make sure that every item in the array gets initialised *by the programmer*.
But what if the programmer wants to create an `ArrayList[T]`? In that case the programmer *naturally* wants to over-allocate a bit, e.g. create an array (backing the list) with space for 16 (or so) elements, even when the list doesn't actually contain any items, yet. Again, if `T` has a default value, you can handle it safely, just initialise all the array items immediately after allocation. If `T` doesn't have a default value, you can't really initialise the array items when allocating the array, you have to rely on the programmer to do so. But then you want to make sure that every no array item is *read* before it has been initialised *by the programmer*, *somehow*. (I don't really have an idea how.)

#programming #programminglanguages #RocketLang

My pet programming language, #Rocket, now supports a simple "raise" statement by which you can raise exceptions.

E.g.:
```
raise StopIteration()
```

The parenthesis can be omitted, too, in which case a new instance of the exception will be created with no parameters.

So far, exceptions could only be thrown by built-in functionality such as integer division (e.g. `1 \\ 0`). To make exception properly accessible in user-written code, I had to replace some "language magic" to make stuff properly accessible in the code.

#programming #programminglanguage #programming_languages #programminglanguages #RocketLang

#RocketLang update:
#Rocket (my pet programming language) now supports break and continue statements in loops. \o/