Skip to content
This repository has been archived by the owner on Mar 10, 2022. It is now read-only.

Specification Flaws #4

Open
PiggyPiglet opened this issue Sep 3, 2020 · 3 comments
Open

Specification Flaws #4

PiggyPiglet opened this issue Sep 3, 2020 · 3 comments

Comments

@PiggyPiglet
Copy link

PiggyPiglet commented Sep 3, 2020

Elara Language Specification

This uses ANTLR Grammar Syntax to describe all elements of the Elara Language.

Would definitely be worth linking to antlr's documentation, as personally, I don't fully understand this specification (my points below are made from educated guesses, or examples), and I assume others may not either.

Names and conventions

Types have names in PascalCase, and should be short and simple, eg Int, String, Person

Short and simple, yet you've got String there? Why not Str? If String is necessary, why not Integer? Just not a fan of integer being shortened, while other types aren't. For example, in java, integers are the only primitive type that are shortened, whereas all the other primitives, and their wrappers, use the full word. There's absolutely no reason why this should be the case. Not to mention, shortening like that is never useful imo, and usually just results in less readable code.

For longer identifiers, kebab-case should be used, eg print-values, for-each, add-1

For multi-word identifiers. Also, it's important to note, that-this-format-of-text, is not universally recognised as kebab-case, unlike other formats, for example camelCase. While honestly, it's obvious what kebab-case is, perhaps a specific definition of it would be appropriate, merely for absolute clarification.

Types

Structs are data-only types composed of multiple properties

Consider making a glossary, for jargon like this.

Simple Syntax

let [name] = [value]

There's is a fundamental inconsistency with this syntax. As far as I can tell, two points can be argued here. The first, is that this statement is a mix of traditional programming syntax, and english itself. Before continuing with that argument, I need to make an important distinction clear, obviously languages borrow a plethora of words from english, however they have absolutely no syntactical value, they are merely keywords. The syntax would not be affected whatsoever if said keywords were replaced with collections of symbols from other languages.

So, the actual first argument, we've got a mix of traditional programming syntax, and english. The english part of this expression, is the let keyword. Now, you could argue my point from before, that this is merely a "borrowed" word from english. The problem with that counter argument though, is that the borrowed words I mentioned before always make sense in the actual code. For example, in kotlin, you've got var/val, which represent variable/value. let, has absolutely no meaning unless you consider this statement as an english sentence, instead of code. The only thing I could think of that let could represent, is letter, but obviously that's not the use case here. The traditional programming syntax here is the use of =, which is why I consider your syntax inconsistent. To be consistent, = could either be changed to be, or equals, to match that of the english language, OR, let could be changed to a more appropriate keyword; my vote is.... drumroll, none at all ([name] = [value])!

Perhaps all of the above is redundant, because you were simply following the syntax of arguably the most universal language? mathematics. let [name] = [value] is undoubtedly recognisable as mathematical syntax, so, if that's the case (elara's syntax is equal to that of mathematics), then surely we'd expect that the rest of Elara's syntax is equal to it's mathematical counterpart? Well, obviously this isn't the case. Jumping ahead a bit, to the function syntax,

let is-overage = (Int age) => {
    if age >= 18 => print "you are overage, yay"
    else => print "too young loser"
}

this obviously doesn't follow mathematical syntax. In fact, mathematical syntax doesn't even have a direct alternative to the above, the only part you could (mind you, partially) recreate is the function declaration (f(x) = ?), but none of the encased logic.

I'm well aware that let isn't unique to this language, it's quite universal in fact, finding it's way into many other languages, including swift, and javascript. This does not excuse it's terribleness though.

let is-overage = (Int age) => {
    if age >= 18 => print "you are overage, yay"
    else => print "too young loser"
}

This isn't from the spec, rather from an example, but as I mentioned before, I don't really understand the spec, so it's easier for me to comment on this. IMO, this is quite a mouthful. To start off with, the let argument from before also applies to this, and my personal recommendation is to simply not have any prefixing keyword. Apart from that, just generally not a fan of the syntax, = [type] => {logic}, it's ugly. Don't have any suggestions either for it sorry, perhaps consider something more traditional.

Structs

I don't understand the format, can we get some comprehensive examples?

Generics

Another little inconsistency. Earlier, structs were extended using extend, yet generics use : to represent the generic as a subtype of the specified type.

Need sleep, might expand on the above two seconds tomorrow, or might not, idk.

@bristermitten
Copy link
Member

Would definitely be worth linking to antlr's documentation, as personally, I don't fully understand this specification (my points below are made from educated guesses, or examples), and I assume others may not either.

Yeah, I can do that. It's the only grammar syntax I'm familiar with.

Short and simple, yet you've got String there? Why not Str? If String is necessary, why not Integer? Just not a fan of integer being shortened, while other types aren't.

I agree that too much shortening is not useful, but I think Int is a special case - all the C based languages (as far as I know) and Kotlin use Int instead of Integer, and so I think it's a well known abbreviation. There's a fine line between too verbose and too concise, but I think Int strikes a good balance. Having something like Str on the other hand is:
A) Not easy to pronounce
B) Not immediately obvious what it refers to.
Of course, for something like this there's a degree of subjectivity, but that's my personal thoughts on it.

For multi-word identifiers. Also, it's important to note, that-this-format-of-text, is not universally recognised as kebab-case, unlike other formats, for example camelCase. While honestly, it's obvious what kebab-case is, perhaps a specific definition of it would be appropriate, merely for absolute clarification.

Good point. I'll add a detailed description.

Consider making a glossary, for jargon like this.

Will do.

You make some interesting points regarding the let [name] = [value] syntax. Again, here is my thought process when designing the syntax:

  • Ideally the code would be read out as "let [name] equal [value]", which I think is a lot clearer than val, var or anything else.

  • While it is inspired by English, so is most syntax that is designed to be readable. Python uses and, not and or for boolean logic rather than the traditional symbols, but it doesn't go for a syntax that looks exactly like actual speech. As far as I'm concerned, programming syntax should take inspiration from speech but still be in a form that is concise.

You suggested using equal or be instead of =. While initially this might seem like a good idea, in complex use I think this would fall apart. For example, reassignment. Should it be done with x be 4, x equal 4, or x = 4? If we go with one of the first two, it looks wrong, and also no longer makes sense if we're considering it as speech. If we use the last, we now have a total inconcistency that will make the language more difficult to learn.

Incidentally, the same problem would arise with the syntax [name] = [value]`, without a specific syntax. In this case, declaration and reassignment are exactly the same syntax. There's therefore ambiguity as to whether you're creating a new variable, or changing an existing one. Further problems would arise if you consider variable shadowing.
For example

name = "something"
names.for-each((it) => {
    name = it.name
    name.something()
})

Are we creating a shadowed variable name, or reassigning the existing one?

Frigga (the previous language I designed) used this syntax and I found it caused more problems than it solved.

In my opinion the only viable alternative to let would be def, but I think that's less clear than let is.

Apart from that, just generally not a fan of the syntax, = [type] => {logic}, it's ugly

I guess this one is personal preference. My reasoning behind this syntax is that functions would be declared identically to lambdas, therefore making learning the language easier and a more consistent syntax (since functions are just lambdas with a name). If there was a different syntax, let's say something like

func name(Type name) : ReturnType { }

While it might be clearer, this raises a few other problems:

  1. In terms of functions being first class, doing something like list filter func-name would indicate that func-name is a variable, when in fact, it's not declared as one. As such you'd be implicitly declaring a variable for every function.
  2. For lambdas, would the same syntax be used? If so, that's overly verbose, and if not, we're back to the inconsistency again.

I don't understand the format, can we get some comprehensive examples?
Yep.

Another little inconsistency. Earlier, structs were extended using extend, yet generics use : to represent the generic as a subtype of the specified type.

I think the reasoning here is that "subtyping" isn't true subtyping. The extend syntax was originally for defining extension functions, but we decided later on that pseudo-inheritance would be useful too. The easiest way to do this, we thought, would be inside the extend block.
While this could create the wrong impression (as it's not actually inheritance, rather just a copy of all of the properties), I think concistency is more important than a small potential misunderstanding.

Regarding the type parameter syntax, I think : is a good balance, since
A) it's already used in variable declaration for explicit type specification
B) adding another keyword (for example extends) would be much more verbose. The as keyword could be reused (eg <T as Int>, but I don't think that would create the right impression either.

Overall you make some good points, but I think the majority of the changes would either make the language more inconsistent, or add an extra degree of complexity to reading and learning the code.

@BomBardyGamer
Copy link

BomBardyGamer commented Sep 5, 2020

I'd imagine that Int has been shortened to such due to Kotlin doing exactly the same, and I imagine Elara's stdlib is kinda similar to Kotlin, whereas String is still the full name in Kotlin

@bristermitten
Copy link
Member

We're nowhere near to creating a standard library yet, however yes, the reasoning behind Int is similar to Kotlin's: familiarity for people familiar with C based languages, while not having 2 different types of type

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants