First some context. There's a pretty cool old(er) game about exploration, colonization and programming called Colobot that got opensourced recently (github) and I found out that it has a somewhat active (Polish) community and they're working on improving, fixing, porting, etc. the game.
Now, this was one of my favorite childhood games and I had literally dozens of different visions as to how a potential sequel could look and decided that it's always better to do something than do nothing and just talk about my ideas, so I started with what I know best(better than 3D graphics and physics at least), which is programming language design (and also happens to be my favorite topic in all of IT, just how cool is that?) and work on designing an educational but powerful programming language.
A question most people would ask is why I won't just use Python or some other simple language. I say: While many of these languages are good, simple and powerful, I believe that if the main focus is going to be simplicity and encouraging good practices, it's possible to do better than Python.
Features that I decided upon are:
-
Class and interface based polymorphism(single inheritance for classes, multiple for interfaces)
-
C++ or Java style syntax rather than Python-style
-
Smart comparison operators - 1 < 2 < 3 evaluates to (1 < 2) && (2 < 3) and not (1 < 2) < 3 or 1 < (2 < 3)
-
Operator overloading and default comparison operators compare by value
-
OOP as the primary paradigm(as you might have already guessed)
-
Members need to be declared, no object.somerandomthing = 56 loosiness like in Python
-
UTF-8 and unicode all the way, pretend byte strings don't exist
-
No implicit member access - only this.member
-
Code completion provided by the compiler like in Haxe
-
Not only errors and warnings, but also notices for bad practices(like accessing linked lists via [] inside a loop)
-
Specifying whether a member is public or private is mandatory.
-
Strings, integers and other simple types are immutable.
-
Iterator-based iteration, iterator as an interface. Few classes - forward, bidirectional, maybe also random access..?
-
No relative imports, only package based - "import cur_project.something", "import std.regex", "import library.somethirdpartylib.SomeClass"
-
std(standard lib), system(system stuff, as much as possible platform independent), library(third party libraries, in the game they will be downloadable and share-able via an interface), project name for importing something from workspace(ingame it will mean programs installed on the robot or building), this for current project if you need to be explicit e.g. "import this.system", no root otherwise("import MyClass")
-
All of standard lib is to follow good coding practices, be commented well, utilize no hacks. Performance is a third class citizen.
-
Class name = file name and you shouldn't need to create them manually in the IDE - there are packages, directories and classes they contain, files are just a detail that is to be as irrelevant as possible.
And some features I'm not so sure about(or ones that I received mixed feedback about so far)
-
Add enums or just allow switching on strings instead? (performance is not even remotely a concern)
-
Should this(or self or whatever else I decide upon) be a reserved name or should it be passed as first argument like in Python?
-
Static typing. I'll probably do type annotations for function arguments anyway, but should I do static typing everywhere or just go with declaring functions and variables via "var a" or "function derp()" ?
-
Generics. IMO they might be somewhat cumbersome and confusing for newbs, and this is one of my main doubts about static typing. On one hand static typing is almost always an extremely good practice, but on the other, it makes many things much more complex.
-
Ad-hoc structures - tuples and the like. How should they look like if I decide on static typing?
-
FP - should I add map, filter, lambdas, generator expressions, comprehension syntax, etc. or not? On one hand they're elegant and often good things to use, but on the other it's just more
-
Syntax for type annotations - should I do "var a: Type" or "Type a"? Trivial but I just can't decide.
-
Mandatory argument labels - no sin(0.5), but sin(deg=90) or sin(rad=0.3), no robot.radar.find("human", 5, 0, 500, 50) but robot.radar.find(type="human", count=5, min_dist=0, max_dist=500, max_vert_dist=50). This is so far the most controversial feature out of all I planned - opinions of people I asked are split pretty much exactly 50-50. My stance is a strong yes - it makes everything much more readable, allows for unit-based overloading(mentioned sin(deg) vs sin(rad), for example), means you don't have to look up every single small function when reading code, makes for natural optional arguments and the additional typing can be mitigated by simple IDE autocompletion
-
Should I have a common base class or just magic functions(toString, hash, operators, etc.)? I've heard some people voice strong disapproval of forced inheritance(and personally I don't want to have something crucial to subclass just to have people ignore it)
-
Global functions and/or variables or not? What about only constants? Should I go the Java/Haxe way and use static members and utility classes instead? Personally I think the latter is the better choice.
It will come with an editor(both desktop one and later when the game is in the works an ingame one) that will contain builtin documentation, tutorials and tips. Think step-by-step tutorial that describes:
-
Basic usage and how things work
-
Advanced usage and related terms
-
How it relates to existing programming languages, how it's usually used and what the best/worst practices are
-
Additional resources or even just trivia for those interested
It will also have "challenges" that tackle all kinds of problems, even ones as trivial as "how to iterate a hashmap and keep track of numerical index". Ideally I'd like it to be a complete learning environment teaching good practices and solutions to all kinds of problems. Of course, it'll come after I finish the language itself, assuming I do at all. I don't doubt my skills, but I do doubt my mind(I've been heavily depressed for a long, long time now). If you'd like to help me with this project, you're more than welcome to, even if you can't or don't want to code.
Keep in mind that my main principles are:
-
Encouraging good practices and discouraging bad ones
-
Readability, ease of use, staying simple but not feature-deprived
-
Being reasonably powerful and no magic, everything needs to be investigable and understandable and no special cases.
-
Usability as a general-purpose language since it's being made for a game that might or might not be created.
I'm using a self-written pratt praser, and my inspirations include Python, Haxe, C++ (in that order) as well as this excellent article. I'll either execute AST directly or target Parrot or nekovm if I feel like it. No pseudo-code examples and no spec or anything, just some things I'm considering because nothing is set in stone so far.
Using an existing language is also an option, but it's not one that I will consider so sorry for the long post and thanks for reading.
This will be my first attempt at making a "serious" language, so I'd be really, really grateful for any feedback you guys could offer. Thanks.