Skookum Syntax - is there a room for improvement?


#1

Hi, Guys,

I’ve mentioned that the biggest turn-off of adopting SK initially is the unconventional syntax. I think SK is very clever in many cases and I really like them but even these days, it’s still a love-and-hate at the same time. It seems like some design choices are random and I don’t see why you chose the unconventional cases. Well, I tried to give some feedback in the past but I never got a response so here I’m trying again. ^^

I consider SK still in the development and early stage for wider adoption. I still think we can improve them by making it more appealing to others. Unless it’s written in stone, I hope not, I think there is some room for improvements. I split the feedback into two sections, one that requires syntax changes and other that doesn’t require.
I hope we can at least support some.

A. Improvements that requires no syntax changes

  1. Adopt CamelCase, or at least keep Unreal function name as is. This is one of the most annoying things. It makes the long function names even longer and also we all have to type longer names forever. Another bad side-effect is that there are name collisions in automatic name conversions to snail cases. Lastly, when there are many strings, such as foo(a_b c d_e_f g h) it’s hard to distinguish if they are separate arguments or not since the spacing is the same and we must carefully look at underscores.

  2. Get rid of [] block at least for a single statement. For a single statement, [] is totally redundant. Getting rid of it will make the code much cleaner. It will also make the syntax more consistent, e.g. [] is always required but for blocks but “unless” and “when” do not require []. I’m not sure what the differences are.

B. Improvements that may require syntax changes. There are several syntax decision that seems like a random. I believe switching gears are bad and I hope SK follows more conventional syntax.

  1. I really don’t understand why you chose [], instead of more conventional {}, (). I keep mixing them up. I know Smalltalk uses [] but SK doesn’t look like Smalltalk other than it uses []. And who cares about Smalltalk these days. Another problem is that [] is used for both blocks of code and grouping. I think it’s better to separate them out and to use {} for the block, and () for grouping. We can use [] for the list instead.

  2. Bring “when”, “unless” to the front. “if” and other conditionals always comes to the front. Bring it to the front will make the code flow more naturally and it makes the syntax more consistent.

  3. Use “cond” for muti-conditional “if” just like you mentioned that it is similar to Lisp Cond. Using “if” for the multi-purpose makes the code hard to follow.

There are several other minor requests but I tried to focus on ones that are important.

Thank you very much and I hope I hear some feedback.

Long live Skookum!!
Cheers!


#2

As someone with now about 2 years of :sk: code across a few projects that are within a year :crossed_fingers: of realizing market, I’ve seen your posts and knee-jerked a reaction of horror at loading a new version of :sk: and seeing thousands of syntax errors pop up.

Breaking syntax changes for me would effectively put me on an island where I’d be unable to upgrade. I’m not a big studio, I only have to manage 2 other developers. We’d never upgrade :sk: again until we started a new project and then we’d wonder whether there’d be another breaking syntax change half-way through the project. So I can imagine what a AAA customer would think about this topic :slight_smile:

I thought I’d at least chime in on some of the ideas that you carefully outlined.

I actually love the :sk: capitalization convention because I believe that case insensitivity saves time. I hate that C++ is case sensitive, bIsOnCooldown != bIsONCooldown, DoLogoff() != DoLogOff(), in many ways it’s patronizing (I don’t need that level of uniqueness) and it has wasted more of my life than I care to admit. In many ways it feels like the language is trolling me.

I will say that just the other day I had the auto-:sk: function renaming get me. I had just written a function GetCurrentPage() and couldn’t for the life of me find it and then … ah current_page. I’m not in love with it, but I am somewhat used to it now.

I’m curious if you have examples of the name collisions you’re getting. Are they auto-renamed functions clashing with variables (seems the more likely scenario)? Or are they names that only vary by a few uppercase letters (seems unlikely and easy to avoid)?

This seems like a good place to use the optional commas to improve readability foo(a_b, c, d_e_f, g, h) or multi_line, which seems very readable to me.

foo(a_b
    c
    d_e_f
    g
    h)

The main difference between the if and when is that if expects a code block whereas when expects only a single expression (a code block is just a group of expressions). My guess for this, and the reason I typically use when is that it’s a little shorter for instances where you only need to call a single expression. Although you can still do stuff like below, it’s arguable how sensible it is:

!a : 0
println("hi") when [a++ println("let's do this") true]

Will print

let’s do this
hi

So really, when and unless are exactly what you’re asking for, they’re versions of if/!if that do not require a code block.

I will agree that sometimes grouping can get ugly with all the brackets for certain equations, one that nags me a little every time is loc + [dir * magnitude] which would just be loc + dir * magnitude in languages with precedence rules.

I don’t have strong feelings on the [] but I do like the advantage of replacing any block with… any block and I also like that there’s no accidental early termination of function call by placing 1-too-many parens as I might accidentally do in code like this if it used () for grouping:

result : Vector2!xy(
      (((2.0 * viewport_coordinates.@x) - w) / w)) // <-- oops
      (((2.0 * viewport_coordinates.@y) - h) / h))

This seems more readable to me, maybe I’ve been tainted :open_mouth:

result : Vector2!xy(
      [[[2.0 * viewport_coordinates.@x] - w] / w]
      [[[2.0 * viewport_coordinates.@y] - h] / h])

Also, I can’t tell you how often I get back into C++ and try creating a new variable Boolean bIsJumping (should be bool). As someone jumping back and forth all day, I really appreciate some of these syntactical differences, because I will make mistakes.

I think I’ve already been biased, I’m used to reading do this thing when some condition is met.

I’m not following this one. Can you give an example?

I’ve seen you post this a few times now, so you must feel quite strongly about it. :sk: blends into an ocean of languages I’ve learned in the past as far as syntax goes, but it stands out as a gem for the most convenient, most time saving and most fun/exciting language I’ve ever used. Until using :sk:, I had never felt the desire to evangelize a language :mage:. That also means I want it to get better, whatever evolutionary path that ends up being.

Side-tangent, I think the only time I ever had the thought “hmm, this seems unconventional” is when I went from 8051 assembly to x86 :nerd_face:.


#3

Hi, thanks for your reply. I appreciate someone actually cares.
I consider myself still new to SK and I’m planning on using SK for a while once I commit.
I guess I can live with the current syntax but I really want SK to be more widely adopted. Once I start working on a full project, just like you have said, I probably don’t want any changes due to all the code modifications I will have to make.
I thought SK is still in development stage and this is probably the my last chance to make the appeal. I’m sure it will help to bring more users to SK or quickly get used to it.

I really can’t stand seeing SnakeCase all over the places. It’s long, has collision issues, hard to tell if it’s SK code or Unreal code, makes already long Unreal function name even longer, type more and etc. “,” in between doesn’t help when reading existing code. It’s hard to reading function with many arguments. If we can’t change to CamelCase for all functions, my petition is to just make Unreal function name the same. It will at least help to distinguish Unreal function from SK.

[] is being used all over the places and it makes the code quite a bit ugly to fresh eyes. And forcing [] to use even for single expression is error proned and cumbersome to type. The use of [] instead of {}, () is probably a random choice and I can’t think of a good reason other than making confusing. Least we can do is that we can reduce the usage by making optional. If it doesn’t break the current code, it won’t hurt anyone, don’t you agree? I’m not a fan of Indentation for code blocks but in SK, I rather use Indentations than []. I think we can support [] or Indentation block at the same time if we can be clever. First, if there is [], use the normal blocks using [], if there is no [], it can be either single expression or Indentation blocks. It can be a workaround until retire the use of [] later.

Cond is multi-conditional If and it came from Lisp. I was saying to just to use the name Cond when you want to express muti-conditional If, rather than having multiple usages of a single function name. This is just a general request to make the code more conventional if possible. I think in designing in APIs or Language, orthogonality, being consistent, and intuitiveness are good design guidelines. SK is very unique and I like many of its features but I feel that it’s little too unconventional and it’s hard to see the benefits other than making it bit confusing.

Cheers!


#4

Thanks for the continued suggestions, care and detail that you have presented @chrisk414!

Here are your earlier related posts for others to reference:

Apologies for not responding sooner. Each time you’ve posted we’ve been in the middle of big tasks that were taking up big gobs of time for our little team - including right now. :madsci: We will get to each point eventually.

I’ll give some feedback on your (@chrisk414) specific points soon.

Also - thanks @error454 for your perspective on things!

We are big on evolving the language and we have a long list of planned extensions. As @error454 mentioned, we are very hesitant to make breaking syntax changes. Additions can be fine. Likewise a worthwhile breaking change that might be fixable with a global file search and replace could be considered - though it does give concern especially to existing teams.

Every syntax choice has some reasoning behind it. It can be hard to know in advance which ones may be popular or not. Changing something to try to increase popularity is tricky because it is often hard to know how effective it really may be. For example say some change results in 10% more people liking Sk. There might be some feature of UE4 that if we hook it up would make 30% more people jump onto using Sk.

Consider:

  • new widely used UE4 feature hooked into the language or IDE - increased happiness 25%-40%
  • changing a symbol used in some part of the syntax - increased happiness -5% - 15% or ???

Please keep offering suggestions - some will stick!


#5

Thank for the reply,

Yeah, I understand that you have to allocate the resources wisely. But breaking changes such as Syntax would be difficult more and more down the road even if we really want. If we were to make breaking changes, it’s now or never. Or is it too late?? That’s why I sound bit too attached to it but I’m just doing my best for everyone’s benefits. I find myself using SK for a long time 5+ years and I want it to be as efficient as possible.

Cheers!


#6

I agree and understand.

It is stuff like this that keeps me up at night…


#7

I wanted to add a note that although auto-naming convention uses all lowercase letters for methods, :sk: still seems to allow case sensitive variables. The IDE will allow you to create a method with case sensitivity but then things start to get weird after that, presumably because the filesystem is case insensitive.


#8

I would prefer a more Lispy language myself but I think Skookum syntax is a lot better than most OOP languages.

I think the block style is influence from Smalltalk if I am not mistaken.

I think the block syntax works well in an expression based language like Skookum.


#9

I’m the biggest fan of Lisp and it has the most clean syntax in my opinion, period. Besides the syntax, there isn’t anything that can mimic Lisp macros . It’s basically programable programming language, easily let you create a new DSL. It’s perfect language for games because it often requires DSL. It’s hard to believe that it is designed in 50s and many of it’s features are still being copied even these days but there isn’t anything that can even come close to its macro system and metaprogramming features. I can go for a while but having Lisp like syntax would require total rewrites. Right now, I’m not asking much but just to make it little less painful. Cheers!


#10

If :sk: was a lisp like language, I would be having wet dreams every night…


#11

You should try out Red, pattern matching macros and reader macros, without the lisp syntax. It also has something akin to fexpressions, which basically make macros a higher order construct.

For lisps with interesting meta programming facilities, try kernel lisp or Shen.