proj-oot-ootSyntaxNotes8

In [1], you see that for Python, () is much more common than []. So imo their functions should be switched ('[]' for grouping, '()' for a data constructor).

what about {}? [2] shows that, for C, '()' is more common than {}. So we can use '[]' for grouping, '()' for a data constructor, {} for () () (){}{}{}(){}

---

regarding the idea of leaving out the letters:

c,f,q,v,x,y,z

it might be a little too idiosyncratic.

I think in normal language we can do without q,v,x,y,z. But you see x,y,z in programming and math all the time (programming tends to use x,y,z as default names for variables, probably because math does, and i bet math does because X is easy to write using chaulk, and Y and Z relatively easy and also next to X -- and maybe also because they AREN'T used so much in normal English). Are people going to do without referring to x- y- and z- axes? Especially in computer graphics (z-buffering, etc).

and 'c' and 'f', although the stats say they are not so useful, feel like very 'normal' letters to my brain; the idea of leaving them out seems weird. Phonetically, 'c' is easily replaced by 'k' and 's', but 'f' is essential. And because 'c' comes near the beginning of the alphabet its absence would be noted (it's not the ABCs anymore, after all).

v and z are also phonetically essential, although uncommon.

We could use a,b,c instead of x,y,z for default variable names, but then we'd have to leave in 'c'. Or, we could use i,j,k. Or, we could make do with only two default variable names ('a' and 'b').

If we only leave out q,v,x,y,z, then out alphabet still has 21 letters, which is too many for some forms of air typing. We want 20 at most.

i guess my current idea is to put 'f' back in there, and leave out:

c,q,v,x,y,z

the default variable names are 'a' and 'b'.

People will laugh when we name our functions 'kall' instead of 'call' but if i asked them to give up 'find' and 'for' they might not just laugh but flat-out refuse to use the language.

but now i am still asking them to give up 'view' and 'vector'? Sounds like a big ask.

note: this points out that you could take out f, and just use 'ph' instead: https://www.quora.com/What-is-one-letter-in-the-English-alphabet-we-could-get-rid-of-and-be-fine-without . I don't like putting elementary sounds in two letter combinations though, that's harder to learn.

note: apparently Asimov and Feynman were both in favor of spelling reform: http://www.benespen.com/journal/2017/4/19/the-long-view-richard-feynman-and-isaac-asimov-on-spelling-reform

note: i must say though, i like Mark Twain's (maybe not so serious?) proposal: https://www.plainlanguage.gov/resources/humor/spelling-in-the-english-language/ , which makes use of the redundant c,y,x to represent ch, sh, th

---

gotta have 'infixify' like Haskell does to allow infix usage of user-defined alphanumeric fns

---

should we have unary operators? K used to have these (and ordinary arithmetic does; ! for not, - for negate, etc), but in Q (an update to K), all unary operators are alphanumeric function names, so at least one person decided they are bad.

---

"A composition a1a2…an of adverbs preceded by a verb v is interpreted as the verb (…((v a1)a2)…)an (adverbs apply in left-to-right order, transforming v in stages). The Examples section below illustrates this." " -- [3]

we can do this with our single-letter-caps HOFs

---

in K, the anonymous fn syntax is:

{[p;q;r]5+p*q-r}

if you don't want to bother with the lambdas (the parameter declarations), you can use x,y,z for the first 3 parameters:

{x+5*y-z}

i like this, although for us it conflicts with {} for scoping, so think about that. But since we are maybe eschewing x,y,z and c, let's make it 'a' and 'b' as the default variables. If a function needs 3 parameters it should declare (this makes sense b/c you probably need to think about explanatory variable names if you have 3 parameters anyhow).

what if you have two anonymous fns nested one inside the other? I guess the 'a' and 'b' are local to the innermost nested anonymous fn without explicit parameter declarations. If you need to access a parameter from an enclosing fn inside a nested fn, then one or the other of those fns must declare params explicitly.

Also, what about '_'? I was thinking that _ might also convert the local scope to an anonymous fn. But we could just use _ as a default variable, and only allow one default variable instead of two (because __ is hard to distinguish from _). That's not crazy; it's a little hard to read anonymous fns with two default variables (also, you have to read thru the whole fn to see if it mentions 'b' before you know if it takes one or two arguments!).

So maybe just use '_', not 'a' and 'b', not 'x', 'y', and 'z'. Less convenient but also more explicit. Otoh we could also use _1 _2 _3, etc. Also, what about using _ to indicate 'dummy parameter that will not be used'? We could still use it that way within explicit parameter declarations.

or mb ? instead of _ so we don't have to use the _ character

---

still want a way to do right-to-left evaluation (in contrast to the default haskell-y left-to-right)

and/or clojure's -> (threading macro, also https://clojure.org/guides/threading_macros )

---

i guess we need an operator for 'compose' ('o') so that we can succinctly do:

f o g o h

(rather than o f $ o g h (which is o(f, o(g,h)))

Haskell uses '.' but we want to reserve that for __get__/__set__/object traversal/graph traversal.

Function composition is associative but not commutative. String or list concatenation is also associative but not commutative. So maybe use '++' for both of these? (or maybe '', because both of these are like matrix multiplication? but is harder to type on a qwerty keyboard, so stick with ++). We could also use '..' but we wanted to use that for either comments or for graph hyper-traverse (that is, to go to the hyper-edge connecting a node with its edge).

We could also make a rule that the '++' operator, although it can be overloaded, must be associative, and the '+' operator, although it can be overloaded, must be commutative and associative.

---

K has 'each' (map), but also 'right' and 'left' modifiers to 'each' so that it can be each-right or each-left (i think). I think you can even have both each-left and each-right to do a cartesian product of two lists. [4] (search for each-left and each-right in that web page)

i think the idea is to have an infix operator (e.g. concatenation), and then to map it over a list, where the list to be mapped over can appear to either the left or to the right of the infix operator.

---

K seems to have list literal constructors with multiple levels of separators; space on the lowest level, and then ';'; this is a lot like what i envision [5]

i wonder if we should have multiple modes for the list constructor () to indicate whether spaces separate elements or not? We could select the modes with a prefix character before the '(', like Python's r"raw string".

eg

s(1 2 3, 4 5) -- a list of two space-separated lists (f 3, g 2) -- a list of two items, each item being the result of a function evaluation

---

K has syntax for self-reference within an anonymous function ('_f'): " Flattening a list:

{:[@x;x;,/_f'x]}

    ‘Flattening’ means obtaining a list of all the atoms of a list – no matter how deep they are nested in its sublists – preserving the relative order in the original list. The above function is recursive and implements a straightforward logic: in a conditional expression, if the argument is an atom (@x), x itself is returned; otherwise the same function (_f is a name for self-reference) applies to each (note the adverb ', ‘each’) item of x, and the results are collected together in a single list by joining them (,/)." -- [6]

---

some quick, good thoughts on identation style:

https://dev.to/edelvalle/python-beyond-pep8-16g6

---

J's "fork" syntax probably useful but I think it's too complicated/hard to remember for beginners

---

In k, Verbs evaluated right to left (right associati vity), adverbs left to right. Haskell function application is left associative which makes sense for partial function application. so maybe for we want function application to be left associative and "adverbs" (single letter caps) to be right associative

Actually you don't need right to left parsing if you have function composition

---

civility 1 day ago [-]

I think one of the most amazing parts of Racket, and one of the reasons someone should try it out if they haven't, is that the source code and evaluator support images and not just text. The following link shows one aspect of this:

https://docs.racket-lang.org/quick/

Just being able to put an image in a comment explaining your algorithm into your code would be huge improvement over the traditional syntax colored ascii you get with most languages and editors. There are many times I've written an algorithm which is difficult to understand without the associated diagram I drew on the whiteboard or in an image editor. Racket lets you insert that image or photo directly into your source, and I think this is a significant improvement over putting a link to that image in a comment.

Racket also goes a step beyond that by letting images be values which can be assigned to variables or returned from functions. The link above shows this clearly. I'm sure there is some value in this as a teaching aid, and I think that's why they did it, but you can also return mathematical plots from your functions and so on. This feature is similar to the various interactive notebooks people use for Mathematica or Python, so it's not really specific to Racket, but it is interesting to play with.

Obviously there are downsides to putting images in your source. After you do that, your code is no longer ascii, and it won't be something you can edit with vi, emacs, or any non-Racket IDE. Also I doubt it will play nicely with git any time soon. However, it's a neat feature of Racket whereas many of the other benefits in the article apply to any Scheme (Chez, Gambit, Chicken, Guile, etc...) or lisp.

I wish there was some reasonable standard (like a better version of Rich Text) that was commonly adopted so other languages could put graphical pictures in the source code.

---

Rust's extern/use syntax looks pretty good, eg:

" extern crate syntax; extern crate rustc; extern crate rustc_plugin;

use syntax::codemap::Span; use syntax::parse::token; use syntax::ast::TokenTree?; use syntax::ext::base::{ExtCtxt?, MacResult?, DummyResult?, MacEager?}; "

Notes:

---

in order to allow infix operators that are

1) easy to type 2) descriptively named

we need to have some symbol that you can prepend or append to an alphanumeric identifier to infixify it.

Haskell has `infixify`. That's pretty good but it would be nice to have a more common character. And also maybe to only have to type it once instead of twice: `infixify

---

foobarbazetc on May 18, 2017 [-]

First thing I noticed. The map entry syntax:

"Foo" to "Bar"

Is also nonsensical. What's wrong with ':'?

ptx on May 18, 2017 [-]

It's because to is an infix extension method, whereas : is not a valid identifier name (and so can't be used as the method name) and you can't define arbitrary operators like in C++ and Scala.

The to method constructs a Pair object from its arguments, so

  "Foo" to "Bar"

is just a prettier way of writing:

  Pair("Foo", "Bar")

The mapOf function (which is just a normal function) takes a variable number of Pair objects as parameters.

---

solidsnack9000 on May 18, 2017 [-]

Some of the conventions:

    // Type indicated with `:`, type follows variable; value follows type.
    variable: Type
    variable: Type = "value"
    // Generics with <>
    strings: List<String>
    // Operator overloading.
    text = "a" + "b"
    num = 1 + 2
    // Capitalize type names.
    class TheClass { ... }
    // Use braces for delimiting.
    class TheClass { ... }

---

pmontra on May 18, 2017 [-]

Some considerations on the syntax (Swift first, Kotlin last in each pair)

    bad: \(apples + oranges) # using \ is looking for troubles 
    good: ${apples + oranges}
    good: label + String(width) # even Ruby requires a .to_s here
    bad: label + width # surprises will follow
    good: ["Anna", "Alex", "Brian", "Jack"]
    super bad: arrayOf("Anna", "Alex", "Brian", "Jack") # make the long form optional
    good: for index in 1...5 {
    bad: for (index in 1..5) { # the useless ()
    bad: extension Double { # why do we need to be so explicit?
        var km: Double { return self * 1_000.0 }
    good: val Double.km: Double get() = this * 1000

---

http://nilhcem.com/swift-is-like-kotlin/ https://leverich.github.io/swiftislikescala/

---

i was talking about allowing all-caps to escape macro hygenicity, should we do that? or should they be keywords?

---

since the presence or absence of whitespace is significant in Oot, what does a+b mean? maybe it means (a+b). In which case a+ would mean (a+) and could be a shortcut for Haskell-style 'sectioning' ie partial function application applied to infix operators.

---

i like using 'use' instead of 'import' like Rust, b/c it's shorter. But unlike Rust (and Python), i want to default to be to not have to qualify the imported things with the library name, because it's shorter. But we still want a way to do qualification-needing imports. We could have 'use' and 'import' but then it's slightly hard to remember which is which. How about 'use library' for a qualification-needing-import and 'use library::*' for the qualification-not-needing one? I'd have to give up my desire for the qualification-not-needing to be the default, but it's easy to remember this, because the semantics of 'use' are 'separately import each thing specified here as a single name'.

we should also have an 'include' facility for those times when you just have some metaprogrammy boilerplate that you need in a bunch of files.

---

instead of Rust's syntax for constructors (eg String::new(); this is an 'associated function' which is Rust's name for a static method), just use Python's (eg String()), which is syntactic sugar for String::new().

---

nineteen999 17 minutes ago [-]

One thing I still like about Perl is how well the regex syntax is integrated into the language, combined with being installed in just about every Linux modern Linux system, makes it really accessible from your fingertips.

If you're in a hurry and just need to do some one-off slicing and dicing, there's not much more powerful than being able to say, eg:

  $data = "foobarfoo";
  $data =~ s/bar/baz/g;
  print "$data\n";

versus python's more dramatic and formal:

  import re
  data = "foobarfoo"
  data = re.sub('bar', 'baz', data)
  print data

For some reason, the Perl =~ notation sticks in my head much more easily than the Python method.

Of course you can string a bunch of sed commands together in a shell script as well, but I find that becomes unwieldy pretty quickly in a lot of situations.

reply

---

we also need an unuse to unimport stuff thatbuse imported (mainly for programs that dont want substd) mb call it nouse instead of unuse? nah, thats hard to read too.

---

. could be compose when freestanding, but structure element selector when attached. this allows you to write readline . expect for err checking like in the rust book number guesser [7], while still using it for structs and methods.

---

" Something I noticed at the time was that the syntax for functional languages tends to be verb then noun: f(x), whereas the syntax for object oriented languages tends to be noun then verb: x.f(). At some level these can be considered equivalent. You can express with one what you can express with the other. There's a big difference in usability though: auto-complete.

What happens when we auto-complete f(x)? First we need to know all possible f that are valid in this context. "

---

https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax

---

from HN thread on Bel: https://news.ycombinator.com/item?id=21236624

excessive 34 days ago

parent favorite on: Show HN: Bel

This one seems backwards to me:

    (2 '(a b c))

In addition to being data structures, I like to think of lists/arrays as functions which map integers to the contents. This nicely generalizes to hash tables / associative arrays, and then further to actual functions. If that's all reasonable, then

    ('(a b c) 2)

is the right order for application.

However, maybe pg is just thinking of 2 as a shorthand for cadr or similar.

pg 33 days ago [-]

Initially I would have preferred that. I did it that way in Arc. But since functions are lists in Bel, I couldn't do that, or you wouldn't be able to call a function on a number. ...

me: my take on this is that you can have lists work like functions (which take an argument that is the selector) as long as functions and lists are different primitive types.

---

the above thread continued with:

pg 33 days ago [-] ... As often happened with things I was forced into, though, I not only got used to putting numbers first but started to prefer it. It means for example you can compose them with other callable things.

e12e 33 days ago [-]

Am I reading that right, that:

  (2 '(a b c))

Is equivalent to:

  (second '(a b c))

And that would work for strings as well:

  (5 "Hello, world!")
  > "o"

Which in turn means 'car and' 1 are equivalent? (probably means 'car should be thrown out, because surely '1 is clearer?

Ed: and with some notation to differenciate "element at N" and "tail behind N" you could get even more mileage out of integers? And then to generalize to lists of lists to reference elements and sub-sections (sub dimensions, like cubes) of matrices?

Not sure what would be nice, perhaps star or ellipsis?

  (1... '(a b c))
  >'(b c)
  ('(1..) '(0..2)
    '(
      (a b c)
      (d e f))
  >'(
    (b c)
    (d f))

Or something?

pg 32 days ago [-]

It would not be clearer to use 1 instead of car when you were using a pair to represent a tree, rather than a list, and you were traversing the left and right branches using car and cdr.

me: this is a good point; you have things like car and cdr anyhow so why not replace them with a numeric notation, which can be done without introducing more syntax if you like numbers act like functions like car and cdr.

And in fact apparently clojure does both of these things; the thread continues with:

andreareina 33 days ago [-]

It seems to be borrowing from clojure, in which both (field container) and (container field) do the same thing.

---

 pornel 1 day ago [-]

Rust did copy C syntax to a large degree. It didn't copy some of the mistakes such as type declarations, which are hard to parse (typedef makes AST depend on itself) and hard to understand ("array of function pointers" is a head-scratcher in C, easy in Rust).

reply

masklinn 1 day ago [-]

Aside from the feedback loop, C-style decls also make the language less regular in the presence of type inference as you need an "inference pseudo-type" to take the place of the type you're omitting.

Also prefix casts have similar issues as prefix type + typedef.

reply

---

therein 1 day ago [-]

I appreciate the ability to avoid having to enclose my conditions in parenthesis, and the main operand of statements like match, switch etc. to not be wrapped in parenthesis.

reply

---

ux 3 days ago [-]

Is there any plan to deal with the locale fiasco at some point?

Some hints on what I'm referring to can be found here: https://github.com/mpv-player/mpv/commit/1e70e82baa9193f6f02...

Unrelated, but I also miss a binary constant notation (such as 0b10101)

reply

OnACoffeeBreak? 3 days ago [-]

I know that we're not voting, but I miss a binary literal very much. I would also like a literal digit separator to improve readability. Verilog Hardware Description Language does that with an underscore [1]. For example, 0xad_beef to improve readability of a hex literal, and 0b011_1010 to improve readability of a binary literal.

1: http://verilog.renerta.com/mobile/source/vrg00020.htm

reply

---

https://gleam.run/

"

pub type Tree(value) { Leaf(value) Node(Tree(value), Tree(value)) }

pub fn any(tree: Tree(a), check: fn(a) -> Bool) -> Bool { case tree { Leaf(i) -> check(i) Node(left, right) -> any(left, check)

any(right, check)
  }}

pub fn has_even_leaf(tree: Tree(Int)) -> Bool { any(tree, fn(i) { i % 2 == 0 }) }

"

---

https://www.researchgate.net/figure/The-modern-QWERTY-keyboard-layout_fig3_237105161

---

Other commentToEol ideas: ,, ;;

---

Gleam only has eol comments

---

gamegoblin 11 hours ago [–]

Much of the original Bourne shell was written in C that had been macro'd to look like Algol [1].

E.g.

    /usr/src/cmd/sh/mac.h:
    #define IF      if(
    #define THEN    ){
    #define ELSE    } else {
    #define ELIF    } else if (
    #define FI      ;}
    
    #define BEGIN   {
    #define END     }
    #define SWITCH  switch(
    #define IN      ){
    #define ENDSW   }
    #define FOR     for(
    #define WHILE   while(

[1] https://research.swtch.com/shmacro

reply

---

https://templeos.holyc.xyz/Wb/Doc/HolyC.html#l36 prints strings all alone on a line

---

https://templeos.holyc.xyz/Wb/Doc/Welcome.html#l73 allows functions to be called without parens (in which case they take their default args) because then the language is a good shell language, too

---

mb each individual expression is like forth, but assignment still exists using =. So x = 1 2 add. but i think that's not that much different from Haskell: x = add 1 2 so haskell is better than this

---

https://news.ycombinator.com/item?id=23747190 ...document <= 'Hello!' # write in the DOM...

Q: why use the operator <= to build the tree of DOM elements? This is not pythonic!

A: Python has no built-in structure to manipulate trees, ie to add "child" or "sibling" nodes to a tree node. For these operations, functions can be used; the syntax proposed by Brython is to use operators: this is easier to type (no parenthesis) and more readable

To add a sibling node, the operator + is used.

To add a child, the operator <= was chosen for these reasons:

> it looks like an augmented assignment because of the equal sign

No, it looks like a comparison. This is totally subjective.

> it can't be confused with "lesser or equal" because [...] would be a no-op

Wrong, the value of _ variable contains the result of the last expression. What value can i expect here?

> we are so used to interpret the 2 signs < and = as "lesser or equal" that we forget that they are a convention for programming languages

I agree, and trying to be subversive won't change that convention.

> in Python, <= is used as an operator for sets with a different meaning

The implementation is different, but the math are the same. The "<", "<=", "==", "!=", ">=", ">" operators are comparison operators.

"setA < setB" has the same meaning as "numberA < numberB", aka: a comparison between two object in an ordered space.

> the sign < is often used in computer science to mean something else than "lesser than", [...], << means left shift; in HTML tags are enclosed with < and >

You are talking about a character not an operator.

> Python uses the same operator % for very different operations: modulo and string formatting

This PEP ( https://www.python.org/dev/peps/pep-0292/ ) tries to replace % as an operator, because it should not be used for string formatting.

reply

---

https://opensource.com/article/20/7/d-programming


i really like the idea of, instead of { } for blocks, having keywords imply {, and replacing } with freestanding .

someone said Erlang uses . 'like the end of a sentence', i'm not sure if that is what they meant though

attached . can still be field reference

---

comparison of Lisp and Haskell syntax showing that Lisp can do qsort concisely too:

https://gist.github.com/cataska/2717986

---

thinking about how to save on parens/curly braces by allowing keywords to delimit blocks, eg:

if CONDITION then BLOCK else BLOCK end

as-is, i don't like this too much because we want the user to be able to metaprogram similar things, but then it's hard to know what the user-defined keywords are.

ideas:

    The advantage of closing say an if statement with .fi inatead of just . Is that .fi could implicitly close any other open blocks within the if. ... .fi. For example:

if. CONDITION .then. BLOCK .else. while. CONDITION .do. BLOCK .. is equivalent to: if. CONDITION .then. BLOCK .else. while. CONDITION .do. BLOCK .fi and in the latter, you can edit BLOCK without having to edit the number of periods at the end of it

---

why Lisp's homoiconic is good for metaprogramming in one author's opinion:

"(1), the correspondence between code and AST should be direct to the point of being almost trivial. ... (2) Lisp should have lists as a central data structure. Lisp thus has many operations to manipulate and analyze lists. (3) complementing and completing the first two, is that code should be represented as a list." -- http://mnielsen.github.io/notes/parentheses/index.html (i reformatted a little)

wikipedia says "A language is homoiconic if a program written in it can be manipulated as data using the language, and thus the program's internal representation can be inferred just by reading the program itself.", suggesting that the value of (1) is just that you don't have to remember (and compute particular instances of) the mapping between the language and the AST

---

one of the ideas for Capitalization was that you might need to Capitalize metaprogrammy stuff like macros. But, i see in elisp that some commonly typed things can be macros (eg 'when'), and in fact we'll have a lot of that b/c we are trying to build our language from a small core using our own metaprogramming.

can we loosen this requirement a bit? The idea being that if the macro is just a little shortcut, like lisp 'when', then it can look like a function, but if its basically an interpreter for a whole new dsl, then it needs to be capitalized for understandability. Some ideas along this line:

---

" Lisp uses prefix notation, whereas Forth uses postfix: "(+ 1 2)" vs. "1 2 +" for example. The use of prefix notation semi-requires delimiters to be inserted, giving us Lisp's beloved/hated parenthesis. With Forth, all computation revolves around the stack. Because the operation always occurs after the parameters are pushed, you don't need the delimiters. Words simply consume whatever parameters from the stack that they want to. One implication of this, however, is that you can do things like "(+ 1 2 3 4)" in Lisp. In Forth, this ends up being either "1 2 + 3 + 4 +" or "4 3 1 2 + + +". "

hmm this makes me think... actually even with haskelly syntax you COULD have variadic functions.. Two ways ways to do this:

1) A function which is variadic in its signature takes as many arguments as it can, up to other syntactic delimiters (parens or ;/EOL) or 2) A function which is variadic in its signature takes as few arguments as it can, but then if there is a type error (because there are too many arguments and not enough functions; that is, the overall 'expression' resolves to more than one value juxtaposed, you backtrack and give the (most recent?) variadic function more arguments)

i think for Oot, i prefer the former.

---

https://keli-language.gitbook.io/doc/ points out that Haskell etc are missing:

---

A prefix sigil for shell-like syntactic access to files/fileglobs

e.g. in bash we can say

for f in *; do ls $f; done

or even

for f in testfile1 testfile2; do ls $f; done

mb in oot we'll say something like

for f in ; do ls $f; done

for f in *testfile1 *testfile2; do ls $f; done

---

if we have haskell like syntax with space-separated function arguments, then how do we do optional keyword args?

We could do:

f key1=value1 key2=value2

but then what if f's output is another function that takes optional keyword args, how do we know which keyword args f consumes and which ones are left for its result to consume?

mb need to use a period or comma or something to separate:

f key1=value1 . key2=value2 means (f key1=value1) (key2=value2) (well not quite, it also means that f stops taking optional args when it hits that enclosing parens, which isn't obvious)

alternatives:

f key1=value1 ; key2=value2 f key1=value1 , key2=value2

could use 2 semicolons for EOL:

f key1=value1 ; key2=value2;;

or could use . for EOL

f key1=value1 ; key2=value2.

or could use . for 'end':

if x then y;; .

or could use .. for 'end':

if x then y. ..

---

i like 'fn' to introduce a fn defn, and i like Golang's idea of space-separating parameters and their types:

fn foo(bar int) {}

---

(my note: sounds like advantages rather than disadvantages to me, but useful to think about):

pornel 21 hours ago [–]

• Rust is focused on being explicit rather than pretty/elegant. So there's sigilisitic code like `&/&mut`, `move

`, `Arc<T>` for details that are implied in higher-level languages.

• Rust wants to have easy-to-parse unambiguous syntax. This makes turbofish required when you have a type in expression context. You need `->` for the return type.

• Rust uses generics, and angle brackets are ugly. It also mandates `{}` in blocks, but allows skipping `()`, which gives you a high ratio of ugly brackets to the nice round ones :)

• Rust wants to make up for the cost of explicitness by adding abbreviations. So you have `fn` that's both explicit and terse. Instead of verbose `switch/case/default`, Rust's `match` uses patterns and `_ =>`.

Rust designers pay a lot of attention to the syntax, but it's designed from a very practical point of view (it is clear? unambiguous? easy to write? composes with other syntax?), and "does it look neat?" is very low on the priority list.

reply

feoren 20 hours ago [–]

You sound like the kind of guy who prefers CoffeeScript? over JavaScript?; YAML over JSON. Every single programming language has punctuation -- the "punctuation-free" languages have all just decided that their punctuation should be invisible.

reply

---

yknow, since it's harder to type capitals, maybe require capitals for 'naughty' things, things that we want to discourage. Such as:

mutability, throwing exceptions, panics, aliasing, other side effects, metaprogramming esp. full reader macros; (and it's worse to define meta stuff than to use it; so maybe using macros is lowercase but defining them uses capitals)

i kept thinking we should have something like Hypercard's 'user level' and that part of that could be to discourage naughty features, but maybe making them slightly harder to type (and very visible) is better.

we can still use sigils for some of these (e.g. & for aliasable/mutable variables); those involve capitals too, anyway

so yeah, mb the Kernel stuff (VAU, WRAP, UNWRAP) could be all-uppercase; reader macro definition could be all uppercase (or maybe this stuff could be prefixed with a sigil). Mb reader macro use could be all-uppercase.

---

CyberDildonics? 8 hours ago [–]

Zig purposely does not parse carriage returns or tabs. When this is brought up, people tell you to use a separate program to format it before compiling and don't seem to acknowledge that this is not a problem with any other language.

The result is that by default you get errors on windows with hello world programs. People will tell you to just change your defaults in your text editor to not write carriage returns. There seems to be a lot of rationalizations from a very unpragmatic choice.

reply

---

spease on July 18, 2019 [–]

I’m comfortable with C/++ and Java, to a greater extent than a lot of people I’ve worked with. There are still things in Rust that are papercuts:

IMHO the frustration involved in these things is not typically worth being more explicit. The :: thing may seem a bit pedantic, but it is simply more physical effort (Shift-colon-colon vs dot) and creates more visual noise.

If/when all of the things above are addressed, I think Rust could give Python a run for its money.

---

"IMO the most alien thing it ((Rust)) has in terms of syntax is the use of a single quote for lifetime parameters ('a), but even that is based on the type parameter syntax for already existing languages (OCaml, F#, Standard ML)."

---

skohan on July 18, 2019 [–]

I had experience somewhat counter to this. I learned C and C++ first, and when I first started working with Java things like CamelCase? did seem a bit strange and off-putting to me, but I got used to the less keystrokes surprisingly quickly, and it's one of the things which bothers me most about working with Rust.

I think there is such a thing as liking what's familiar, but there are also design decisions which are simply easier to read or easier to parse. Another one would be semicolons: I have never missed semicolons one bit in a language where they're not required.

kybernetikos on July 18, 2019 [–]

> I have never missed semicolons one bit in a language where they're not required.

I dutifully wrote semicolons for years, but just a short stint of Scala and I don't like using them anywhere now.

---

pjmlp 10 hours ago [–]

I just dislike the way stuff gets imported const std = @import("std").

Too much require.js look alike.

reply

someziguser 10 hours ago [–]

In Zig the source files you are importing are implicitly structs. Personally I find it better to keep it consistent, declaring it like any other struct with the use of a built-in function. I don't think there's any advantage to turning it to a typical module import statement given the underlying semantics.

reply

pjmlp 10 hours ago [–]

So Zig won't support binary libraries?

reply

ifreund 10 hours ago [–]

It already does, dynamic linking is orthogonal to @import() semantics.

---

" The release of fish 2.2 brought support for abbreviations to the shell. These are similar to standard aliases, but expand inline to the full command when typed. For example, a command can be shortened to yul using the following:

   abbr yul "yarn upgrade --latest"

"

---

"

I am surprised that it took so long for fish with its focus on UI experience to implement

"
and && as shortcuts for longer ;or/and variants.

---

i like having an 'elementwise' modifier to operations, that works on both unary and binary operators

---

consider having flexible quotes like Perl:

kbenson 12 hours ago [–]

If only more languages supported quote operators like Perl. They really do make certain things like this so much easier.

Non interpolating quotes:

  q/I wasn't surprised when he said "boo" and game me $5/;
  q@I wasn't surprised when he said "boo" and game me $5@;
  q!I wasn't surprised when he said "boo" and game me $5!;
  q(I wasn't surprised when he said "boo" and game me $5);
  q[I wasn't surprised when he said "boo" and game me $5];

Interpolating quotes:

  qq/Hello, $name!/;
  qq!Hello, $name\!!;
  qq@Hello, $name!@;
  qq(Hello, $name!);
  qq[Hello, $name!];
  qq'Hello, $name!';

Rule of thumb, single q for single quote string (non-interpolating normally), and two q's for a double quote string (normally interpolates).

reply

---

use punctuation for: syntax (eg {}), common and/or abstract infix stuff (eg elementwise, map, =), common stuff (e. #)

---

I is infix "in"

---

mb some commands autoquote their arguments or otherwise treat them differently from std oot. for example dplyr commands take variable names unqouted ( https://r4ds.had.co.nz/transform.html ). for example shell takes filenames unquoted. these could be indicated by capitalizing the commandname.

dplyr even allows expressions as arguments: filter(flights, month == 1, day == 1). perhaps this is just to say that macros should be capitalized? but i dont think mere template macros, or delayed evaluation macros, necessarily need that. but is there a difference between those and the dplyr example i gave?

mb what i am talking about is 'reader macros'?

---

mb have some punctuation reserved for 'infix reader macros' (takes control of the whole parse out to surrounding delimiters?)

---

another R/dpylr metaprogramming syntax example:

"# Select all columns except those from year to day (inclusive): select(flights, -(year:day))"

---

mb leading dash to infixize? then what would indicate privacy? caplitalization to export? that doesnt seem right.

we are already using underscore for negation. i guess both right dash and right underscore are unused tho. also underscore isnt a great negation bc we want underscore on its own to be saved for trash argument or for lambda argument.

mb if we are making connected and disconnected things different anyhow Then we may as well use left dash for negation like usual

---

sigil for dynamically scoped variables

---

  1. something is a command to he language implementation (pragma) or preprocessor. # comment is a 2eol comment (note the space). ##something is a 2eol comment.

metaprogrammable infix sigil prefix could be ! or ^ or *, for memory. but for typing mb choose stuff near the edge for the most common things. so i had been thinking # for preprocessor and language cmds, and ^ for annotations, but mb thats a bad choice,.

---


Footnotes:

1.

 means left shift; in HTML tags are enclosed with < and >

reply

linkdd 1 day ago [–]

I'll try to explain why I strongly disagree with the FAQ:

> this is easier to type (no parenthesis) and more readable

When 99% of the open-source codebase uses "<=" as lesser-than-equal, no it is not more readable to change that.

> It has the shape of a left arrow

Then, why not `child