Conversation
Edited 21 days ago
programming shitpost
Show content

languages like Clojure and Common Lisp are designed so that everything is an expression, but in my new language, (C++)++, everything defaults to being a statement instead. if you’d like to turn a statement into an expression, just prepend return:

int foo() {
    return 1337;;
}

int addOne(int n) {
    return (return n) + (return 1);;
}

int factorial(int n) {
    return if (return (return n) == (return 1)) {
        return 1;;
    } else (return if (return (return n) > (return 1)) {
        return factorial(return (return n) - (return 1));;
    } else {
        error(return "invalid number");;
    });;
}

you may have noticed (C++)++’s revolutionary new return if expression syntax. in (C++)++, an if ... else statement simply evaluates its condition and both bodies (whether the condition is true or not) and then discards the results. but a return if ... else statement instead acts like a ternary operator in other languages:

// this evaluates to `1`!
return if (return true) {
    return 1;;
} else {
    return 0;;
};;

in fact, a return if ... else expression is just syntactic sugar for the ternary operator:

return (return true) ? (return 1) : (return 0);;

you may have also noticed that many lines in (C++)++ end with two semicolons instead of one. this is for two reasons:

first, (C++)++ has a revolutionary “automatic semicolon removal” system. while your code is being compiled, the compiler will automatically remove all of your semicolons and then guess where they should go. this is very easy to do and should be fine

second, (C++)++ comes bundled with a new type of operator known as the “double semicolon operator”. here’s how it works:

 // when a double semicolon is inserted at the end of an expression, with no expression in
 // front of it, it evaluates to the expression on the left
 return 1;;
 // ^ this evaluates to `1`

 // when a double semicolon is used to separate two expressions, it evaluates to the
 // second expression
 return 1;; return 2
 // ^ this evaluates to `2`

 // and finally, the double-semicolon operator is left-associative, and can be chained
 // forever if you want:
 return 1;; return 2;; return 3;; return 4
 // ^ this is the same as (((return 1;; return 2);; return 3);; return 4)

curly braces are ignored by the (C++)++ compiler. instead, the language uses significant whitespace. including curly braces is still considered best practice, however, to avoid scaring C++ developers:

 // avoid doing this:
 int collatz(int n)
     return if (return (return (return n) % (return 2)) == (return 0))
         return (return n) / (return 2)
     else
         return (return (return n) * (return 3)) + (return 1)

 // instead, do this:
 int collatz(int n) {
     return if (return (return (return n) % (return 2)) == (return 0)) {
         return (return n) / (return 2)
     } else {
         return (return (return n) * (return 3)) + (return 1)
     }
 }

also, make sure to add lots of double-semicolon operators, so that C++ devs will feel at home:

 // this is even better:
 int collatz(int n) {
     return if (return (return (return n;;) % (return 2;;);;) == (return 0;;);;) {
         return (return n;;) / (return 2;;);;
     } else {
         return (return (return n;;) * (return 3;;);;) + (return 1;;);;
     };;
 };;
2
15
25
programming shitpost
Show content

@kasdeya query: does (c++)++ have concepts like [classes, inheritance, objects]? neocat_floof_devil

1
0
1
re: programming shitpost
Show content

@catgirl_so it does! specifically, each class must be its own file, which is organized like this:

// Animal.cpppp:
return class Animal {
    private string sound;;
    // this declaration does nothing, but it helps to reassure C++ developers that an
    // object's fields are private in fact, `private` is treated as an alternative to `//`
    // for starting line comments. `#` is another way to start a line comment, and so is
    // `--`. also, any line starting with `/*` or ending with `*/` is treated as a comment

    return void procedure new(string sound) {
        this.sound = return sound;;
    };;

    return void procedure speak() {
        print(return this.sound);;
    };;

    return string procedure getSound() {
        return this.sound;;
    };;

    // make sure that `Animal` evaluates to itself
    return this;;
};;

this file will be compiled to a binary called Animal, and you can use it like this:

// main.cpppp
object kitty = return (new (return "Animal.cpppp")((return "nyaaa!")));;
// ^ this will create a new `Animal` process which we can communicate with over stdin and
// stdout using JSON-RPC! all objects in (C++)++ are represented by their own processes.
// that way, concurrency will be easy!

kitty.speak();;
// the `Animal` process has just printed `nyaaa!` to its `stdout` stream. this is very
// confusing to our `main.cpppp` file, which is expecting a JSON-RPC response over stdout
// instead, and will cause an immediate crash

kitty.getSound();;
// unfortunately we forgot to print a valid JSON-RPC response, so this method call will
// block forever :(

(C++)++ eschews inheritance in favor of a trait system. to use traits, just use a trait expression in any file:

// anything.cpppp
return trait Pettable {
    return string procedure pet() {
        print(
            (return
                "{\"jsonrpc\": \"2.0\", \"id\": 1, \"result\": \"nuzzles your hand\"}"
            );;
        );;
    };;

    return this;;
};;

now all objects in (C++)++ can be .pet():

object sqlConnection = return (new (return "SqlDatabaseConnection.cpppp")());;
string petResponse = sqlConnection.pet();;
// `petResponse` is now `"nuzzles your hand"`!

string secondPetResponse = sqlConnection.pet();;
// invalid JSON-RPC id!
0
0
4

@kasdeya You can’t do this, they just finished C++26

0
0
1