I don't like the way pragmas are treated in your proposal.. It's a good thing to have them split out a bit (like they are now), IMO, but {. ... .} is a lot of noise. I think just doing {} would be enough separation.
I feel like your proposal is a bit too drastic; some :'s and ='s are a good thing because they create a visual separation that is (in my mind) a bit easier to follow. What Nimrod needs is a bit more consistency... and I know we've talked about this ad infinitum in the past, but it's this:
type Foo: object = # object impl
proc Foo: int = # proc impl
And new recommended coding standards and practices, which our tutorials and samples follow.
It's a good thing to have them split out a bit
filwit said: If your complaint consists of "it's hard to parse cause no symbols" just let me know and i will make a screenshot to prove you wrong
Please use your imagination for color highlighting. I can, and will, demonstrate how ':' make zero difference here (it just means extra typing), but I really don't want to take the time ATM. Things can be just as distinct without the extra symbol.
and I know we've talked about this ad infinitum in the past, but it's this: <snippet>
That isn't consistent with if/else/etc.. nor custom macros which consume Stmt bodies because there the "body" follows ':', which is part of the crux of my arguments for these changes. Ideally OOP macros should feel exactly like type/proc builtins for the sake of popularity among that very large programming crowd.
Or maybe we could just make the following code legal:
import macros
macro foo(a: expr, b: expr): stmt =
# a == PSym(Bar), b == PNode(nkAssign, PSym(nil))
nil
foo Bar =
nil
Correct me if I'm wrong but your aim is to make Nimrod more consistent. In my opinion allowing the user to use {} instead of indentation will accomplish the exact opposite. It's also a very obvious feature which new programmers will notice, and it will most likely discourage them from using the language. There is already evidence of this: many people dislike style insensitivity and it is a similar feature to your proposition.
Using blank space for separation names & types/pragmas is not an issue when you have proper color coding (unlike it's rendered on github). In fact, all it ends up is being easier to type. If your complaint consists of "it's hard to parse cause no symbols" just let me know and i will make a screenshot to prove you wrong.
I simply disagree with this. You are turning Nimrod syntax into C syntax, and I dislike C syntax with a passion. I know that the IDE can highlight this but sometimes colour is not enough. I can very easily skip everything enclosed in {. and .}, it's much harder to skip a variable length list of pragmas when they are only separated by a space especially when the important information (the return type) are also separated by a space. The current pragma syntax is also arguably easier to parse for the compiler, perhaps we should conclude that it's easier for humans to parse as well? I realise that I am being a bit subjective here but it's hard not to be especially when talking about syntax.
Syntax does matter for adoption, but it is arbitrary with many strong opinions on opposing sides (similar to the case-sensitivity issue). So what's important is how easy it is to learn, read, & type and what options the languages has that makes it agreeable to the most people. Which implies two things: Consistency & Familiarity are important, and having less noise (aka, less symbols) is the demonstrably best direction. Also, things like supporting both indent significant and insignificant semantics makes sense for popularity (dom96, please see my note below)
Of course it matters. But it's impossible to please everyone. I know that we can try with "block delimiter insensitivity", but I already expressed why I think that won't work.
As for familiarity. I would like to show you some Scala code:
def factorial(x: Int): Int =
if (x == 0)
1
else
x*factorial(x - 1)
For comparison, the equivalent Nimrod code:
proc factorial(x: Int): Int =
if x == 0:
1
else:
x*factorial(x - 1)
It is extremely similar. Are there languages out there which would resemble the syntax you propose? Scala ticks the "familiarity" box for the current syntax.
Consistency is in my opinion not a problem. The only problem that may exist is that you indeed cannot reuse the type section syntax for macros (@zielmicha proposed a solution for that which I like). I've already explained how I read the current syntax in my head in this gist. I'm not sure what else I could do to explain why in my opinion the syntax is consistent, perhaps it's just habit and I am lying to myself heh.
Nice work filwit, I really like where you're going with this..
Before we move on, I would throw in one thing I think would be really important for this proposal to make more sense: Enforce all type names to be Capitalized, event built in types like Int, String, Seq
I think that would be really good even if this proposal wasn't implemented, but it just makes even more sense with it. Then you're not going to have the argument that you need syntax highlighting to be able to see which part of the statement is the type name.
I'm a big fan of consistency. I'm convinced it relieves a small but significant burden from the brain.
Before we move on, I would throw in one thing I think would be really important for this proposal to make more sense: Enforce all type names to be Capitalized, event built in types like Int, String, Seq
Yes please! That is what I suggested in the beginning of the T/P prefixes removal discussion and I still would love for this to happen, Haskell does this and it works very well in my opinion. Sadly I don't think Araq is a big fan of this idea.
Sadly I don't think Araq is a big fan of this idea.
Maybe we can overvote him.
Although 1 and 2 are semantically different, that is no reason for confusion IMO. Definition one can be contrasted against "=" which, apart from assignment, means "<type name> is defined as <type def>", or "<callable_name> is defined as <body>".
I like how the current syntax gives these symbols general meaning. It improves readabilty.
type TThing: object = ... is also less meaningful than type TThing = object ..., because object means to construct a particular object type. The : is not even meaningful after a type name in a type section, because types do not have type, they are types.
Also, i'm afraid of removing too many symbols. Here's an example comparing haml and jade html templates:
Haml, heavy use of %tag, not afraid of =:
%section.container
%h1= post.title
%h2= post.subtitle
.content
= post.content
Jade, very "elegant" syntax:
body
h1 Jade - node template engine
#container.col
if youAreUsingJade
p You are amazing
Even when syntax highlighted, the Jade template still obscures the difference between template and logic.
I don't entirely like the alternative pragma syntax either. The manual mentions the possibility of having "func" denote a proc with no side effects. This could be done for other cases too, at the risk of having to deal with permutations of different pragmas. I'm pretty sure Araq has some thoughts about this that aren't expressed in the language yet.
Anyway, thanks for writing a nice proposal and giving me the chance to rant.
And before the "Go hate train" attempts to run me over
You can't be in "hate train" for me: you're a Nimrod contributor and you're trying to make the language better.
A little remark about Ref as keyword idea, it can't work for such code:
type Item:
data: string
prev, next: Item
The object can't contain in itself another object of the same size. Though it can be solved by making an exception for this case (ref berore object fields types).
filwit: type and proc make completely irregular use of : and =, and are additionally both different than if/else/etc.
There's nothing irregular here because ":" in proc/var declarations and "=" for types denote different things. "=" is for literal equality, while ":" denotes an "is-instance-of" relation. This is like suggesting to replace the equals sign in mathematics with an "∈" symbol in some cases. You write GF(4) = ℤ₂[x]/(x²+x+1) , not GF(4) ∈ ℤ₂[x]/(x²+x+1).
There's a colon after if/else etc. because Nimrod inherited that syntax from Python, and Python got it from ABC. ABC got it because it was determined through usability testing that people found the code more readable with the colon than without (e.g., what Haskell, Coffeescript, and Occam do).
And the latter is really the crux when proposing a new syntax. You may think that a different syntax is more readable, but you'd have to demonstrate that either scientifically (i.e., through studies) or by seeing widespread adoption in practice. The most common result of employing an unusual, untested syntactic style is for the language to remain niche because it creates an obstacle to adoption [1].
There are really only three basic kinds of syntax that have seen widespread adoption across multiple languages and stood the test of time: C style, Pascal style – especially with Eiffel/Ada comb-style control structures rather than begin/end –, and indentation style (sometimes in a mix-and-match way, such as Scala with C-style statements and Pascal-style declarations, or Nimrod, which mixes Pythonesque whitespace-sensitive blocks with a Pascal-ish declaration syntax).
If you want to propose a new syntax, the burden is on you to show that it actually has advantages in practice and not just as a matter of conjecture. What I'm seeing myself is not a problem with the syntax, but lots of people who have only ever seen C/C++/Java code and have never been exposed to Pascal/Eiffel/Ada/Modula-2/etc. code and thus find the syntax unusual; not because there's anything "irregular" about it, but because it's different from what they are accustomed to.
[1] You will rarely see legacy effects (e.g., Fortran, COBOL, BASIC) trump syntax, but even there you don't see other languages adopting the syntax of those languages; in fact, modern versions of Fortran and BASIC have become more Pascal-like.
jbe wrote: In my own humble opinion, the current syntax is much better.
Thanks for your vote! However, I've actually gotten pretty positive feedback from the few people outside of Nimrod that I've shown, which, weighed against the feedback I've gotten from within Nimrod (which is generally "i don't care", "no one cares", or "why change?") makes me feel I'm on the right track in terms of general popularity.
jbe wrote: 1. "<var or field name> has <type>", or "<callable> has <return type>"
This is not true. First, because <var or field> should be followed with is type, similar to how you later describe : meaning for types. Second, because <callable>'s don't have any types. The naming you're associating with : here don't make sense, as the concept are different. The only consistent definition is...
jbe wrote: 2. "begin block"
... this one. This is the only definition we need, and in terms of typing, is the only way we naturally think of things. Most types aren't inlined tuples or aliases. They're indented blocks associated with the type or proc declaration. However, both these "blocks" currently occur after different symbols entirely, and even place the {.pragmas.} in unique locations. Moreover, OOP macros are very important for adoption IMO, and while they will be used to 'declare' types/procs, they feel like action (if/else/etc) blocks instead.
jbe wrote: I like how the current syntax gives these symbols general meaning. It improves readability.
I disagree it improves readability at all, and I feel my screenshot has effectively demonstrated that as well. However, If you really want more proof, I'll happily make a fake-screenshot where pragmas are very distinctly highlighted (with rectangle borders and different background-colors).
Moreover, the largest programming langues today (Java, C++, C#) pretty much do exactly what I'm suggesting, only as a prefix instead of a postfix. Eg, "public static int something" vs "var something pub glob int". I agree Nimrod makes the very sane choice of putting what's important first (the symbol name), but I don't see a valid argument against using spaces for separation. It's very clear with highlighting, and proven to work in other very popular languages.
jbe wrote: Even when syntax highlighted, the Jade template still obscures the difference between template and logic.
And I agree with that direction really. What's the real difference between a macro and a keyword in a language like Nimrod where macros are almost as powerful? Macros are the only way to support convenient OOP designs in Nimrod really, so that's also a reason to keep them as similar to builtins as possible. IMO.
----- ----- ----- ----- -----
LeuGim wrote: A little remark about Ref as keyword idea, it can't work for such code:
I knew I probably shouldn't have included that part in the example as it was sure to confuse people as to my intent. I have a lot of arguments behind shifting these things around that aren't present in any of my examples so far, but I'd rather no go over all of them at the moment. For now, know that it was never truly my intention to completely remove "var x ref int", but only make all {.pragmas.} (of which 'ref' would become, similar to 'glob' in my comparison screenshot) useful as "keywords" (much like how templates can be used as optional pragmas today). There's a lot more to be said about this issue and my idea of explicit ref/value operators (also shown in the comparison screenshot), but that's talk for another time, and completely separate from my main objectives at this point.
----- ----- ----- ----- -----
Jehan wrote: "=" is for literal equality, while ":" denotes an "is-instance-of" relation.
Accept for types, in which case : has no meaning. And, perhaps more importantly, for custom OOP macros, if/else/etc. See my statements to jbe above as well. In my (initial) proposal, : means "is defined as" consistently for every related semantic item. I don't see how any argument could could be made which favors the inconsistent approach over the consistent one, really.
Also, programming is not Math.
Jehan wrote: And the latter is really the crux when proposing a new syntax. You may think that a different syntax is more readable, but you'd have to demonstrate that either scientifically (i.e., through studies) or by seeing widespread adoption in practice. The most common result of employing an unusual, untested syntactic style is for the language to remain niche because it creates an obstacle to adoption [1].
This I completely agree with, and have stated as much. This is why Araq's design to allow alternative parsers through #! is such a good design, and this is where these ideas will be experimented with, by me, and presented as an alternative until the potential day that you all see the light :-P
Jehan wrote: What I'm seeing myself is not a problem with the syntax, but lots of people who have only ever seen C/C++/Java code and have never been exposed to Pascal/Eiffel/Ada/Modula-2/etc.
I fully admit this is the case, but then, I've repeated many times the need to consider the difference in popularity between the two groups. C/C++/Java/C# are much more popular, and if our goal is language adoption, that is not an insignificant fact. That doesn't mean we just copy what they do, pure democracy is completely silly. But it does make one design better for adoption than the other.
----- ----- ----- ----- -----
Araq wrote: If "consistent, perfect" syntax is so important for adoption, how come nobody has it?
While I appreciate the detailed overview of other language's flaws, and generally agree with them, you're comparing apples to oranges here. None of the more popular languages you list (C#, C/C++, Javascript) suffer from the irregularities between declarations of types/functions like Nimrod does, especially considering the importance of Nimrod's eventual OOP macros. There's no irregular usage of the {} symbols with struct/class in C/C++/C#/Java or even Javascript (if it can even be compared). There is a rather huge irregularity in C++'s meta-programming syntax, but guess what? It's one of it's most complained about features and is largely the driving-force behind some of D's success.
More importantly, I don't really see how "they have flaws too" is a valid argument against "we could improve this, and here's how". I'll happily accept accusations of perfectionism, but then, I'm no longer arguing that this needs to be addressed right now so long as I have the ability to eventually write my own parser and demonstrate it's merits. Even without that, Nimrod's syntax is pretty good as-is, and probably won't hinder adoption a huge amount, if at all. This exact amount this sort of thing will effect adoption remains to be seen, but I do think it would help, based on other common complaints I've seen/heard from others using the more popular languages. Like I've said many times, there are more important issues which programmers care about. But I also know the effects of good advertising, and that largely has to do with appealing to market interest. A demonstrably better product will always trump slick aesthetics, but then, why shouldn't we strive to have both?
dom96 wrote: Correct me if I'm wrong but your aim is to make Nimrod more consistent. In my opinion allowing the user to use {} instead of indentation will accomplish the exact opposite. It's also a very obvious feature which new programmers will notice, and it will most likely discourage them from using the language. There is already evidence of this: many people dislike style insensitivity and it is a similar feature to your proposition.
I'm not arguing for strict consistency in terms of features. I've always been in favor of options which allow programmers to coexist peacefully, like the case-insensitivity. I'm only arguing for consistency in symbols meanings among common Nimrod declaration's use of symbols. My proposal has a universal definition for : and one common usage/placement for pragmas, unlike the current syntax which has three. I also disagree options here would discourage new users. They're already using optional {} in C's if statements very happily. I also don't think the parallels between optional brackets and optional casing apply since the later is mostly complained about due to local/type definition conflicts (and being the culprit for the T/P thing).
dom96 wrote: The current pragma syntax is also arguably easier to parse for the compiler, perhaps we should conclude that it's easier for humans to parse as well?
It's not hard to parse for either. Humans have colors and I feel I've effectively demonstrated this at this point. Compilers (such as C's "public static int x") have been parsing based on spacing for years without problems.
dom96 wrote: As for familiarity. I would like to show you some Scala code:
Add pragmas to your Nimrod code, then compare. Then compare to type-declarations with pragmas and note the differences in symbol/pragma usage.. now lets compare both to a OOP macro which accepts exprs and converts to pragmas (the only effective way to capture the OOP crowd). I think this will effectively illustrate where there inconsistencies in Nimrod are, and it has nothing to do with other parts of the syntax being related to other more popular languages like Scala.
dom96 wrote: The only problem that may exist is that you indeed cannot reuse the type section syntax for macros (@zielmicha proposed a solution for that which I like).
I'm interested in his/her's proposal. Can you link me?
I've thought about the proposal for a bit, and although I find the idea very good, and I really like your way of thinking, I wouldn't cast a vote for it so to speak.
You've shown that it works great with syntax highlighting.. but Nimrod is still a text-based language. If you're going down the road of designing the syntax with the idea that users require certain features from the text-editor/IDE, then I say, why not go further? Why not go all the way? I mean, why are we even having this debate? It's easy to imagine a language where the syntax is irrelevant, and the user can have whatever syntax he/she desires through something similar to CSS.
In fact, Nimrod could be a very good bridge for this line of thinking, because it's somewhat strict about indentation, whitespace and comments, and it's lack of a text-based preprocessor. The mapping between text and AST is quite strong, and the "pretty" tool makes it even stronger. It could be possible to both support pure text-based editing, and simultaneously allowing editors that are intelligently hooked directly into the AST.
I have actually played around with this already. If you dump the AST as XML, you can style that XML-file with a CSS stylesheet, and I've found that you can perfectly reproduce the Nimrod syntax from the AST with just CSS. Then you could easily just make a different CSS with your suggested syntax. Of course, the hard part is creating an editor out of this ..
I'm a big fan of Bret Victor when it comes to this line of thinking, I loved his talk "The Future of Programming": http://vimeo.com/71278954
One think I would like to mention are fixpoints. In
let i: int = 5
the colon as well as the equal sign clearly splits up the lhs/rhs. Removing them to some extend results in less points to start reading. At least I do often not start reading at the beginning or the end of a line but at these fixpoints. This happens especially when I just want to find out the type of a declaration. Focusing only on colors probably would result in worse readability.
Another problem is infix notation (though I don't know if Nimrod supports it).
proc f(t: A ~> B ~> C): C
instead of
proc f(t: `~>`[`~>`[A, B], C]): C
could be a valid type declaration either already today or maybe in future. A missing colon could lead to a lot of parsing problems.