Why `"hello"^true` is allowed?

question

#1

Is there a use case for the method "hello"^true? Why allow exponentiation with a Boolean?


#2

you can write

flag ? string : ""

more compactly as

string^flag

Don’t use it if you don’t like it, but it is harmless.


#3

I see, thanks.


#4

It saves a few characters, at the expense of being harder to understand - if you see foo^bar in some program, your first thought would be that it is exponentiation, not repetition, which is why this sort of punning is frowned upon now (same issue of course with foo*bar)


#5

Another reason not to use string^flag, besides being harder to understand when seen in code, it is 10x slower than using the ?: operator (which on Intel, at least, optimized to just 3 instructions, with no branching at all (using a cmovneq instruction).


#6

I am aware that you don’t like this operator, but I have no intention of restarting #11030 here.


#7

Even Jeff and Stefan how said that doing such punning was not a good idea, and I think it’s important for people to understand the costs, both in readability and performance, of using those operators, when there are clearer, faster alternatives.


#8

I have to say I side with @ScottPJones on this. I don’t like * for string concatenation.


#9

Which is perfectly fine, I was just suggesting not to start that debate again here.


#10

I was just trying to counter what you had said, about it being “harmless”, which (not just according to me) it is harmful for readability, as well as being significantly slower (in case this is in some performance critical code).


#11

str^n is just a different way of writing repeat(str, n), it has nothing to do with the ?: operator. It just so happens that Bool gets promoted to Int. One can easily fix the performance problem by specializing repeat on Bools.

As for this:

I am agnostic about the * and ^ operators for strings, but I think the idea is that exponentiation is repetition, and that the use use of those two operators is internally consistent.

x^4 = x*x*x*x = xxxx.


#12

Yes, and explicitly using a function name that only means one thing makes it more readable, as opposed to using a pun which requires you to figure out just what types the arguments are before you can understand what the code is actually doing.

Having one operator mean both exp and repeat based on the argument types does make the code harder to comprehend, which is my real objection, even if the performance issue were fixed.
If you don’t believe me, ask the creators of Julia, who’ve stated that one shouldn’t use the same name for different concepts.


#13

Please don’t spread this type of misinformation.


#14

Here is a quote from @StefanKarpinski: https://github.com/JuliaLang/julia/issues/11030#issuecomment-96727303

My problem with * for string concatenation is not that people find it unexpected but that it’s an inappropriate use of the * generic function, which is agreed upon to mean numerical multiplication. The argument that strings form a monoid is kind of thin since lots of things form a monoid and we’re generally not using * for them. At the time I introduced * for strings, we were a lot less strict about operator punning – recall | and & for shell commands – we’ve gotten much stricter over time, which is a good thing. This is one of the last puns left in the standard library. The reason ++ would be better is not because it would be easier to learn (depends on where you’re coming from), but because the ++ operator in Julia would unequivocally mean sequence concatenation.

Note that the operator punning is not an entirely academic concern. The Char corner case shows where the punning can cause problems: people might reasonably expect ‘x’ * ‘y’ to produce either “xy” or 241. Because of this, we just make both of these operations no method errors, but it would be perfectly reasonable to allow ‘x’ ++ ‘y’ to produce “xy”. There’s a lot less of a case for having ‘x’ * ‘y’ produce 241 or ‘ñ’, but the sequence concatenation operation does actually make sense.

Please don’t spread misinformation yourself, @kristoffer.carlsson


#15

Easy there, folks. I’d say that this is just as much about having Bool <: Number (#19168) as it is about using ^ for string repetition (latest thoughts there are #22461). Neither is closed. Like it or not, this still isn’t completely black and white. Note that we’re in a usage question, not a Julia design one.


#16

Your argument for saying “this is frowned upon now” is a 2 year old Github comment from a single julia developer?

Please.


#17

There have been many more comments, from a variety of core Julia developers, over the last 2+ years.
That one, from the person who introduced * and ^ for strings in the first place, I felt was pretty convincing.

Are you trying to say that operator punning (and punning in general) is not considered bad Julia practice?


#18

The usage of * and ^ for strings is idiomatic Julia that the official manual recommends. When this change, and the official manual recommends against this, you are free to say that “this is now frowned upon”. Until then you can say “I frown upon it”.


#19

@kristoffer.carlsson is 100% correct. I did write that, but me writing a comment on GitHub is in no way official; I was just making an argument, and I’ve been known to change my mind, be wrong, and even not have my every whim reflected in the language :scream:. Until a collective decision is reached on #22461, using * for string concatenation is not “frowned upon” at all, it is still the syntax for string concatenation and accordingly s^n is the syntax for string repetition.


#20

To be perfectly clear, I said that that sort of operator punning is frowned upon now, which I believe is still the case, whether or not the particular instances of operator punning with * and ^ are officially frowned upon.

I’ve also heard the same about using the same function name for different meanings, from Jeff the first time.
In practice since then, when reviewing other’s code I’ve seen how much harder it can be to read where the same operator or function name can mean radically different things, depending on the types of their arguments.

Do you honestly think that seeing foo^n in the middle of some code is more comprehensible than repeat(foo, n), when the type of foo may not even be given in the function?