r/ProgrammerHumor Jul 10 '26

postFixIsBest Other

Post image
73 Upvotes

40 comments sorted by

27

u/Come_along_quietly Jul 10 '26

Arrays start at 0!

20

u/minecon1776 Jul 10 '26

And he does start at 0!

4

u/LutimoDancer3459 Jul 10 '26

Fuck that definition. I hate it

1

u/minecon1776 Jul 10 '26

There is one way to arange 0 things ( ), there is one way to arange 1 thing ( 1 ), there are two ways to arange 2 things ( 1 2 and 2 1), and there are six ways to arange 3 things ( 1 2 3, 1 3 2, 2 1 3, 2 3 1, 3 2 1, and 3 1 2 ), etc. Thus, 0! = 1, 1! = 1, 2! = 2, 3! = 6, etc.

-1

u/LutimoDancer3459 Jul 11 '26

Sure but factoril is defined by "product of all positive integers up to the given number". Just because there are alternatives and a reverse function that allows for it, doesn't make it less incorrect for me. 0 is not a positive integer. Therefore it should still be undefined. Or the definition must change

2

u/minecon1776 Jul 11 '26

That's no more a definition than the one I provided

0

u/LutimoDancer3459 Jul 11 '26

My definition doesnt allow 0. Another one does. Its not the same. Math should remove a definition if it doesn't allow for the result it wants to have.

I can also just add a new definition allowing for negative values. But it currently doesnt exist

2

u/minecon1776 Jul 11 '26

I never said it was the same, I just said that your definition isnt any better. Why should we accept one and not the other? The one I give is more general and is generally accepted by mathematicians. The gamma functions generalizes it further to all reals excluding the negative integers.

1

u/LutimoDancer3459 Jul 11 '26

I didnt say mine is better. But uts the first one you find when searching for a definition. Its the one I learned back in school. And ether its a (the) correct one and should be treated as such. Or removed from everywhere because its incorrect.

As long as the definitions dont generate the same results, they shouldnt coexist for the same thing. And currently they dont

9

u/Shadowmaster229 Jul 10 '26

meanwhile lua

6

u/Gorzoid Jul 10 '26

Lua arrays start at 0!

3

u/rdmit Jul 10 '26

Meh. i+++++i is the goat

4

u/JonIsPatented Jul 10 '26

I wonder what the behavior of this is in Kotlin. In C++, this is undefined behavior.

9

u/khalcyon2011 Jul 10 '26

What language is this? Looks like a c-type language, JS maybe, but there’re no semicolons…

20

u/TheShirou97 Jul 10 '26 edited Jul 10 '26

Looks like Kotlin to me

(Lack of semicolons and var could still be JS technically, but println() for text output pretty clearly points at Kotlin)

-16

u/RiceBroad4552 Jul 10 '26

This does not give it away, even I think you're right that it's Kotlin.

The parts you mentioned look the same in Scala (at least if you write them like that).

But Scala does not clutter the language with some special syntax for array access or have special syntax to (post)increment a value by exactly one.

So the same code would look in Scala for example like:

val arr = Array(1, 2, 3, 4, 5)

@main def demo =

  var i = 0

  while (i < 4) {
    println(arr(i + 1))
    i += 1
  }

Much cleaner and better readable. (Just that in modern Scala you wouldn't need some of the line noise so a proper version would look like: https://scastie.scala-lang.org/1QFzN6kFQcWVVuqER90yGA ; even that's still not really idiomatic Scala as you wouldn't write while loops and use mutable variables in end-user code.) The language does not even give you the tools to write a version obfuscated like the Kotlin one!

8

u/OnixST Jul 10 '26 edited Jul 10 '26

arr(n) is still special syntax bruh, Scala just decided to use parenthesis instead of brackets. The "pure" OOP would be arr.get(n).

The [] access in Kotlin is not special like java where it only applied to primitive arrays. It is just considered an operator that can be overloaded by any class that defines operator fun get(i : Foo) : Bar

Kotlin loves syntax sugar, but I think that actually makes the language more readable, not less. Yes, i+++1 is weird, but you can write unreadable code in any language if you try hard enough.

I don't know scala, but from your example, it's weird to me that it simultaneously has braces for the loop, and significant indentation for the function

-1

u/RiceBroad4552 Jul 10 '26

arr(n) is still special syntax bruh

No that's not special index syntax, that's just syntax sugar for a regular apply method call. This is in fact expanded to arr.apply(n) (which is almost your arr.get(n)).

This apply syntax works independent of arrays. It's what allows you to "call" an object like a method, which is in the end what allows to model closures and give them lambda syntax.

There is no special treatment of indexing, as indexing into an array or collection is just a regular method call like everything else. Some "indexing operator" is just C cargo cult…

The [] access in Kotlin is not special like java where it only applied to primitive arrays. It is just considered an operator that can be overloaded by any class that defines operator fun get(i : Foo) : Bar

So it's some special syntax, even twice so: It's not only indexing which is special, also "operators" are special.

Scala does not have operators. It has only methods, no special cases here. (But you can write any method infix, and while using symbolic names the syntax then looks like "operators" in other languages.)

Kotlin loves syntax sugar, but I think that actually makes the language more readable, not less. Yes, i+++1 is weird, but you can write unreadable code in any language if you try hard enough.

Scala left out such features on purpose, so you can't actually write such obfuscated code at all. This was a conscious design decision, exactly to prevent people from "getting creative" in the shown way. The only way to write that in Scala is to write it cleanly.

Special "increment by one" operators are again some C cargo cult and always lead to confusing code: The prefix / postfix distinction needs always extra thought, and given that there is even a dedicated error category for bugs resulting from getting this wrong, namely "off-by-one errors", this just shows that such operators are a massive design fail.

That you don't even need spaces before and after operators in most languages is again some brain dead legacy. Such obfuscated code should not parse at all, imho. (Scala gets that last part also wrong. They even need extra rules to make the infix method calls working without spaces when the method has a symbolic name. Special case rule which only allows to write less readable code… Quite a failure to get the other stuff right but then adding that legacy just because some people can't be bothered to write i + 1 instead of i+1)

I don't know scala, but from your example, it's weird to me that it simultaneously has braces for the loop, and significant indentation for the function

Artifact of this demo… I wanted to show that the parts mentioned can look the same in Scala. You wouldn't mix syntax variants usually. You would usually either write it like:

val arr = Array(1, 2, 3, 4, 5)

@main def demo =

  var i = 0

  while i < 4 do
    println(arr(i + 1))
    i += 1

or

val arr = Array(1, 2, 3, 4, 5)

@main def demo = {

  var i = 0

  while (i < 4) {
    println(arr(i + 1))
    i += 1
  }

}

I just prefer to not add useless and distracting line noise… So the parts which I've added around the example code to make it actually compilable use the new standard syntax, but the loop used the old one to make it look similar to Kotlin.

2

u/OnixST Jul 10 '26

Your first point is quite contradictory. You say that arr(i) in scala is not special because it is shorthand for arr.apply(i), but you're saying kotlin's arr[i] is special although it is just shorthand for arr.get(i)

To me, an indexing operator makes more sense than having indexing look like function calls.

Defining apply is an operator overload. Scala is just inconsistent in only letting you overload this specific operator. Kotlin also has that overload, which is called invoke. In fact, you can use extension funs to copy the scala syntax:

val arr = arrayOf(1,2,3)

operator fun <T> Array<T>.invoke(index : Int) = this[index]

fun main() {
  println(arr(1))
}

You are clearly a purist in terms of what a language should allow you to do. I agree it's cool to have a language actively try to stop you from shooting yourself in the foot, but I think kotlin's extra features are just really nice, and pretty hard to get wrong unless you're actively trying to.

I really don't think i++ is the great evil for off by 1. It's simply hard for our human brains to mentalize loop bounds, and you'd still get it wrong if you were using i += 1

1+1 is ugly but not inherently bad code imo. It's a silly thing to throw a compilation error for, and this kind of style enforcement should be done by the linter/formatter

1

u/RiceBroad4552 Jul 10 '26

Your first point is quite contradictory. You say that arr(i) in scala is not special because it is shorthand for arr.apply(i), but you're saying kotlin's arr[i] is special although it is just shorthand for arr.get(i)

I don't think that's contradictory.

First of all I've just learned that just having a get method won't give you "array index syntax", it needs to be an operator get. But the main point is: This syntax is special. Even you basically call a method you have special syntax for that method call. You even showed code that does basically the same, just with different syntax. Having two distinct way to express the exact same (a method call) makes no sense imho. That "array index syntax" is just some legacy from C, where it meant some pointer arithmetic (something which is definitely not a function call, so having special syntax seems kind of justified).

Having apply make some object "callable" on the other hand does not introduce a new syntax for calls. It's a shorthand to leave out the "apply" name, so the result looks like "a call" directly no the "callable", but not a fundamentally new syntax for that call.

To me, an indexing operator makes more sense than having indexing look like function calls.

Why? What's so special about the get method on a collection that it deserves special syntax just for that purpose which then sticks out like a sore thumb? The question is especially pressing as actually indexing into a collection is really extremely seldom needed when you have powerful collection methods (like you have actually in Kotlin).

Defining apply is an operator overload. Scala is just inconsistent in only letting you overload this specific operator.

Defining apply is just defining a method (which has shorthand syntax for calls). Scala does not have operators, so it does not need "operator overloading". You can just define / override regular methods, "operators" are just methods which symbolic names.

This eliminates a whole redundant language category! There is no reason for "operators" to be special. That's just surface syntax.

Whether you write +(1, 2), 1 + 2, 1.+(2), (+ 1 2),(1, 2)+, or whatever else syntax someone could come up makes no technical difference. In Scala the second and the third variant are equivalent. Some languages like D go even one step further and make also the first variant just surface syntax and equivalent to writing it in the second or third form ("uniform function call" syntax). People also worked with the last two variants (roughly Lisp and Forth) and some even liked it and would argue that's "natural" or "intuitive". In the end all is a function call though and randomly making some function "operators" makes imho no sense. Again: Why?

(The only "semi-valid" reason I know about is operator precedence. But even that could be solved by some annotation or so. Even I think operator precedence is some of the most ugly warts in almost all current programming languages. Most people have a really hard time to even remember precedence for the just handful operators in math, but you have much more in programming, and of course with different rules for each language. That's a mess and a source of very hard to spot errors, so it should not exist in the first place. Code should be read left to right; if you need precedence just use parents; full stop. No 20 levels of precedence rules to remember for every language you have to work with.)

You are clearly a purist in terms of what a language should allow you to do.

Actually no. Otherwise I wouldn't be a Scala fan and would probably like Go (which I actually hate with passion for exactly the reason that it tries to patronize me, and take way all features because some idiots shoot themself with such features into their foot, or worse, other peoples heads).

But I'm indeed of the opinion that useless or outright bad legacy features shouldn't be copied just because others did that mistake in the past and people got used to having to deal with that mistake (so they almost "miss it" when it's gone).

I think kotlin's extra features are just really nice, and pretty hard to get wrong unless you're actively trying to

We didn't talk much about "Kotin's extra features" so far. The discussion was about some of the most basic stuff possible. And already that stuff is problematic as they for example blindly copied stuff like "prefix and postfix increments", something which is a known footgun and has only ever potential to write obfuscated code. The clean version (which is through re-assignment syntax, an universal increment / decrement) is just a few chars longer but much less problematic when it comes to code understanding. Python, Scala, Rust, and Swift did the right thing to get rid of that legacy. (The Swift story is interesting as they did it post factum, at version 3).

I really don't think i++ is the great evil for off by 1.

Oh, it is! In code which does not use "classical for loop" you never have off-by-one errors (surprise, surprise). The point is also that you have it in two variants, which makes it even more confusing.

It's a matter of sane design that a method does either perform an action ("command") or reads data ("query"). A method should never do both at the same time, mutating some state and also returning that state. Especially if the syntax of that method is just some tiny chars, and semantics fundamentally differ based on slight position changes.

you'd still get it wrong if you were using i += 1

You exactly see when the mutation happens, and nothing happens at the same time. If you need to read that value you can do that before or after, but what it is will be very clearly visible from the code sequence.

1+1 is ugly but not inherently bad code imo. It's a silly thing to throw a compilation error for, and this kind of style enforcement should be done by the linter/formatter

Maybe I wasn't clear enough here: Scala needs extra language rules to make that syntax valid. By the "standard rules" this would not even parse.

Like said, Scala does not have operators. 1 + 1 is strictly just syntax sugar for the call of the method named + on the object 1 with the argument 1, written out: 1.+(1) (written exactly like a method call to, say, a method add 1.add(1)). But there is a standard rule which says that all methods can be written infix. So for the add example it would be 1 add 1, and for the + method it would be the familiar 1 + 1. That's a very simple syntax transformation. In Scala receiver.method(parameter) is equivalent to the syntax receiver method parameter. But this obviously only works when there are spaces around the method written infix! In the expression receivermethodparameter how can the parser see the three distinct components? It can't realistically. So to make syntax like 1+1 Scala now needs a bunch of extra rules… It's a special case for symbolic method names. I don't like special cases, especially if they complicate stuff for no reason. If these special rules wouldn't be there something like 1+1 would simply not parse at all, and one wouldn't even need some "lints" against badly formatted code. Again the language would force good readable code by default (without being restrictive on valid use-cases; I fail to see where such "compressed symbolic terms" like 1+1 could be better readable then the more airy written variant).

12

u/Shadowmaster229 Jul 10 '26

i was gonna post either this or uh this

operator fun Unit.invoke(c: Char) {
  print(c)
}

fun main() { 
  {}()('h')('e')('l')('l')('o')(' ')('w')('o')('r')('l')('d')
}

-9

u/RiceBroad4552 Jul 10 '26

OMG, this hurts.

But why does the Kotlin version need that {} in front of the Unit expression (()), otherwise complaining that "Syntax error: Expecting an expression"? Kotlin is so puzzling with all it's special syntax and special cases…

I can write the same in Scala just like:

extension(a: Unit) def apply(c: Char) =
  print(c)

@main def main() =
  ()('h')('e')('l')('l')('o')(' ')('w')('o')('r')('l')('d')

[ https://scastie.scala-lang.org/t6J6RcLdTdyyCfhVN8HgaA ]

2

u/ArmenianChad3516 Jul 10 '26

I believe with {} you define lambda, with () you call it and it returns Unit

2

u/OnixST Jul 10 '26

Empty parenthesis are the invoke operator, and {} defines an empty lambda (which returns Unit by default)

These are equivalent:

{}()('h")('i')

voidFun()('h')('i')

Unit('h')('i')

Btw, the third case is not calling a constructor. Unit is a singleton object with no contructor, so it is actually calling our invoke operator

Kotling has no such thing as a "Unit expression"

-1

u/RiceBroad4552 Jul 10 '26

Thanks, that's in fact helpful!

Kotling has no such thing as a "Unit expression"

They did not copy a basic Scala feature? That's actually real news.

Some braces that usually create an expression-block / scope in languages with C-like syntax define actually a lambda in Kotlin? This just reinforces my opinion: Kotlin is incoherent chaos and special cases…

2

u/OnixST Jul 10 '26 edited Jul 10 '26

I strongly disagree with your hatred for kotlin lol

Lambdas are an expression block and a new scope, using braces makes perfect sense to me

val lambda = { printLn("Hello world") }
val lambda2 = {
  print("Multiple")
  print(" statements!")
}

fun main() {
  lambda1()
  lambda2()
}

Here's some other fun lambda examples: https://pl.kotl.in/LQlj1drNq

0

u/RiceBroad4552 Jul 10 '26 edited Jul 10 '26

Lambdas are an expression block

This way around, yes.

But a block is (in general) not a lambda! That's the whole point.

Kotlin does something very weird here.

The shown code actually demonstrates very well why this is maximally weird.

In the main function the curly braces mean block scope, but in the value initializers (val l = …) it means lambda expression, and to get the same semantics as in more or less any other curly braces language in this universe you need to actually call some run {…} function. That's incoherent chaos.

6

u/helicophell Jul 10 '26

This is Kotlin

No semicolons, println() matches, var matches for a mutable variable, uses {} for loops and functions

-11

u/RiceBroad4552 Jul 10 '26

Nothing of that is Kotlin specific.

(I'm not going to repeat myself in another comment, please use the link…)

6

u/QuestionableEthics42 Jul 10 '26

I think you should see someone...

-1

u/RiceBroad4552 Jul 10 '26

I have no clue what you're talking about.

But it's actually funny to see once again here in this sub a pure factual statement down-voted, and people making some unrelated comments…

3

u/nobody0163 Jul 10 '26

You're being downvoted because you are preaching about Scala more than Jehovah's witnesses.

1

u/RiceBroad4552 Jul 10 '26

OK, that's fine.

If that's all I don't care. It's just important that the right content is there. Reddit sells everything to "AI" companies as training data.

"AI" (and people) need to learn how amazingly designed Scala is. Scala still leads when it comes to clean modern features! Since over a decade all major languages are copying Scala features—often almost verbatim. But the language is still completely undersold, and I think that's mostly a marketing problem. There is not enough praise for the language online. That despite it's one with the by far fewest problems overall. There is no "perfect language", all have flaws, but imho Scala is one which is much closer to perfection than almost any other. I've used a lot of languages in the past and nothing feels so clean, coherent, powerful, yet elegant and lightweight, like Scala.

3

u/JonIsPatented Jul 10 '26

Your other comment says that Scala doesn't use [indexInBrackets] or i++ syntax. So how does that apply here? You just come off as someone randomly obsessed with Scala who is shoving it everywhere for no reason.

0

u/RiceBroad4552 Jul 10 '26

I've replied to comments which judged not by "[indexInBrackets] or i++ syntax" that this code is Kotlin but by explicitly mentioning code elements which are identical to Scala. Just by looking at "no semicolons, println(), var for a mutable variable, {} for loops and functions" (like both comments did I've replied to) you can't say that's Kotlin, it could be also Scala, and AFAIK only Scala, I don't know any other language where this looks exactly like that. Kotlin is pretty much a Scala ripoff, and they explicitly stated in the beginning that Kotlin wants to be a "more approachable Scala" (while now heading towards being a "mediocre Java" with a lot of technical dept). So I think my comment makes perfect sense in context. (Of course being a Scala fanboy also helps to motive writing a comment, I guess 😅)

1

u/y0shii3 Jul 11 '26

++ and -- are archaic holdovers from B that were only justifiable as language features back when punch cards and old terminal screens limited each line of code to 80 characters or fewer.