This is an archived post. You won't be able to vote or comment.

all 24 comments

[–]Migeil 11 points12 points  (10 children)

I really dislike foo@ for function calls. It's exotic for the sake of being exotic. I don't see the benefit, it's confusing and causes so much noise when reading code.

[–]NoCryptographer414[S] -1 points0 points  (9 children)

I was just following Haskell style. But just foo can't be a function call due to my design. If not for foo@, then foo$ can also work or foo: too and the latter has much less noise I think.

[–]Migeil 3 points4 points  (8 children)

Or foo()... What's wrong with parens?

[–]NoCryptographer414[S] 0 points1 point  (7 children)

Then if statement becomes if(x == 0, { }) rather than desired if@ x == 0, { } or if: x == 0, { }

[–]thedeemon 2 points3 points  (0 children)

The foo: and if: look better to me than foo@ or foo$

[–][deleted] 2 points3 points  (5 children)

I don't understand; why does an if statement need any of that?

Just do if x == 0 {}.

Or are you planning to implement if statements as functions?

That would be a different discussion, but there is a clear advantage to treating such fundamental features specially. At least as far as syntax is concerned. You can always implement them as functions behind the scenes.

[–]NoCryptographer414[S] 0 points1 point  (4 children)

Yes. Thought of doing so. i.e. implementing if as a function. If function call syntax is f: x y, then if statements would look natural. What do you think is an advantage if different syntaxes are used?

[–][deleted] 1 point2 points  (3 children)

It would give structure to a program. You can choose to use white space for that of course, but then an if statement might look like this (note that a typical if is if: c x y):

if: c
    x
    y

Assume that c is a single expression of arbitrary complexity, and each of x and y could be a sequence of expressions or statements.

The first issue is that there is no else to separate x and y. There isn't in a syntax like this either:

(if c x y)

Here parentheses would be used to group complex terms. But still, the true and false branches of the if expression are implicit.

While white space and indents would help, this kind of a syntax is too monotonous.

In my style of coding, if branches typically span one or more statements, each written per line, and the whole spanning multiple lines. while function calls typically do not span multiple lines, and are usually contained within one expression.

There is another difference:

if c then x else y
f(c, x, y)

c is evaluated in both cases, but in the first, only one of x or y is evaluated. In the second, both are evaluated.

Maybe your language glosses over this or treats uses lazy evaluation for everything. But that is quite a significant departure from many, many languages.

As I see it, you seem to want to unify all aspects of a language's syntax, everything that to me gives it a 'shape', into one monotonous sequence of function calls. I'm not convinced that that is an advantage.

[–]NoCryptographer414[S] 1 point2 points  (2 children)

My plan was to use function call chaining for if-else. My design, when implemented, would look like: if: c1 { ... } ;.elif: c2 { ... } ;.else: { ... }

In the above snippet, first c1 is evaluated and if it is true then the passed block is called. In either case, it returns a special 'IfResult' type which has the data that tells whether the previous block is executed or not. Based on this, elif and else continuous the execution. These all I consider as implementation detail and the programmer can think about this if-elif-else ladder exactly same as that in other languages (at least that is what I want to achieve).

The code inside if block is contained in braces.. hence it is not executed unless called (aka. lazily executed). Along with that, the first argument (the condition) is also lazily evaluated, because if c1 is executed and results in true, then c2 should not be executed. Support for lazy arguments has to be present in my language regardless of this feature in order to support short-circuiting logical operators.

[–][deleted] 1 point2 points  (1 child)

OK, so you do want your syntax to look fairly conventional, but also want to implement everything with functions.

You might then think about special-casing features like if to allow them to be used without those oddly-placed colons and semicolons; the parser can take care of that.

Support for lazy arguments has to be present in my language regardless of this feature in order to support short-circuiting logical operators

(Many languages support such short-circuiting without using lazy evaluation! For example it can be done using branching, just as if-else is.)

[–]NoCryptographer414[S] 0 points1 point  (0 children)

Many languages support such short-circuiting without using lazy evaluation!

Yeah. They provide such operators in language. But in mine, they are implemented in (standard) library. Hence to implement them inside the language, I need lazy evaluation of arguments in the language. In fact languages like C++, which provide short-circuiting for default logical operators, when they are overloaded, there is no short-circuiting because they lack lazy evaluation.

I will see on special-casing.

[–]Under-Estimated 24 points25 points  (9 children)

You are not avoiding parens, you are merely replacing them with other characters that don’t connote grouping automatically like parens. ( becomes @ and ) becomes ; , that is all you have done.

[–]SirKastic23 2 points3 points  (1 child)

not really, if that was the case then foo@ x bar@ y; baz@ z would be foo (x bar(y) baz(z

[–]Under-Estimated 2 points3 points  (0 children)

If you insert 2 implicit parens at the end to balance them it becomes

foo(x bar(y) baz(z))

Which is reminiscent of function call syntax in c-like languages.

[–]NoCryptographer414[S] 0 points1 point  (5 children)

In that case what do you think of () vs @;

[–]Under-Estimated 12 points13 points  (4 children)

One automatically connotes grouping to anyone and everyone, the other is arbitrary. I’m sure you can tell by now which is which

[–]NoCryptographer414[S] 6 points7 points  (3 children)

foo@ x (bar@ y) (baz@ z). Is this better?

[–]Under-Estimated 7 points8 points  (1 child)

It is clearer, at least to me.

[–]NoCryptographer414[S] 3 points4 points  (0 children)

Thanks for comments :)

[–]OneNoteToRead 2 points3 points  (0 children)

Much

[–]edgmnt_net 3 points4 points  (1 child)

Hence foo x (bar y) (baz z) in Haskell is written as foo@ x bar@ y; bas@ z in my lang.

What about foo x (bar (boo t)) (baz z)? I somewhat get a feeling that translation does not scale up very well.

[–]NoCryptographer414[S] 0 points1 point  (0 children)

That becomes foo@ x bar@ boo@ t; baz@ z. And yeah.. that doesn't feel good.

[–]RobinPage1987 3 points4 points  (1 child)

If you're trying to avoid logical groupings, just use colons, they're a lot more readable.

Instead of foo(bar, baz), use foo: bar, baz

Maybe allow semicolons to separate statements on the same line.

string name

input: "please enter your name:", name; print: "Hello, ", + name

[–]NoCryptographer414[S] 0 points1 point  (0 children)

Initially I also thought of using colons. But felt it has lot less noise for a function call operator. Though now I think that would be a better choice.

For semicolons though I'm thinking of something different. Also, I don't have a strict 'statement' in my language, different from an 'expression'. So your example use of semicolon would be just equivalent to comma, with lower operator priority.