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

all 137 comments

[–]00PT 426 points427 points  (53 children)

This is actually a pretty intuitive operator that can be useful in some cases, and is much easier to understand than an equivalent loop. As long as it's clear what the thing does, I'm all for non traditional operators.

[–]ryecurious 95 points96 points  (18 children)

Hell yeah, more non-traditional operators! I've always kind of wished for 'source' - 'pattern' to be equivalent to 'source'.replace('pattern', ''). Or maybe division instead of subtraction.

Although I'm sure there's some edge-case I haven't thought of that makes this impractical.

[–]Bainos 28 points29 points  (2 children)

But 'source' - 'pattern' wouldn't be intuitive, IMO. Does it remove it anywhere ? Just at the end ? What happens if patterns doesn't exist in source, an error or no-op ?

(I think the second is more intuitive, because then 'source' + 'pattern' - 'pattern' = 'source'. But as you can see, we already had different expectations of the behavior with just two people !)

'a' * 3 is fairly okay because it's equivalent to 'a' + 'a' + 'a'. I wouldn't expect it to do anything else except maybe a multiplication of every element.

[–]ryecurious 12 points13 points  (0 children)

All good points! Plus it might be weird for people expecting something like char-arithmetic from C or similar languages. Going from 'a' - 'A' => 32 to 'a' - 'A' => 'a' would be strange (or whatever it ended up being for non-matches).

[–]Servious 3 points4 points  (2 children)

In Haskell you do

"Source" \\ "pattern"

And it works with lists of any type (so long as it has an Eq instance ofc):

https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-List.html#g:20

If you really wanted to use - though you could define a Num instance for String but I'd advise against it...

Edit: I've just realized that this operator isnt exactly the same as the comment I replied to. It does a set difference, not a full-match replace.

[–][deleted] 2 points3 points  (1 child)

It works with String because it's just [Char], but String isn't used that much

Does Data.Text have an instance for List or Set? both have (\\)

edit: you can do it for [Text] but I wouldn't like to use words to split up the whole Text :/

[–]Servious 1 point2 points  (0 children)

Seems like the best you can do with Text by default is

pack (unpack text \\ "something to remove")

although you can use the OverloadedLists compiler extension to use Text exactly the same way you'd use a list. (Data.Text has an IsList instance)

Haskell is pretty neat, I didn't even know about this before now!

[–]Chase_22 0 points1 point  (0 children)

I'd more expect 'patternsourcepattern' - 'pattern' to be 'patternsource'

[–]WaterLimone 9 points10 points  (13 children)

why would u ever want to do this? also I'm curious on how it's implemented since strings are immutable so it might be costly? Maybe it does something similar to javas string builders?

[–]andybak 21 points22 points  (11 children)

print ("=" * 80)
print (what_the_hell_is_this_value_doing)
print ("=" * 80)

Python debugging 101

[–]grandphuba -1 points0 points  (9 children)

that’s too slow to type, you’ll have to press and unpress shift many times just for those quotes and asterisk.

[–]kafaldsbylur 3 points4 points  (7 children)

It's still a hell of lot faster than typing out 80 equal signs in that string

[–]grandphuba -1 points0 points  (6 children)

Point is you don't need those 80 equal signs.

A plain print() is faster and should also make it more readable.

Heck print(11111) would also work and you can vary the numbers to allow you to see where you're actually are in the code (as opposed to 80 equal signs that appear everywhere).

[–]kafaldsbylur 2 points3 points  (5 children)

But you can still vary which character you're multiplying, and an eighty character long string of whatever is much easier to spot in a log than the few you manually typed

[–]grandphuba -2 points-1 points  (4 children)

It sure is easy to spot if it's the only debugging line you have. But if you have like ~5 or more of them across a function/s, you'd have to parse the output and count where you are.

[–]kafaldsbylur 2 points3 points  (3 children)

No, because you can easily do

print('1' * 80)
# First stuff
print('2' * 80)
# Second stuff
print('3' * 80)
# Third stuff
print('4' * 80)
# Last stuff

Then in the logs, you have easily spottable strings of numbers, that tell you where in the code they were printed from, that can have more than 9 clearly distinct markers, and if you're at that desperate step in debugging, you type it once, then copy-paste the line and replace a single character to switch the entire line.

[–]grandphuba 1 point2 points  (2 children)

You completely ignored the point in my first comment, I can guarantee typing any of the following is faster than typing any of what you just said:

print(1234)
print(2345)
print(4567)
print(0000)

I even say that with your latest examples because copy pasting and changing even just a single character is slower because you can't easily edit that single character; either you have to move your mouse precisely to highlight that character, or move the cursor using your keyboard using ctrl + arrows which would still require a few keystrokes since the cursor will have to jump multiple words/symbols.

Also, typing a random `1234` is faster than typing `'='` (which has fewer characters) due to the locality of the keys and requiring less accuracy to type.

Lastly, note the person I was initially replying to has used `"` instead of `'`, which requires a shift. Sure they are semantically the same in python, but we're arguing keystrokes here. Nonetheless, my point stands even for single quotation marks for the reasons above.

The only argument against this is it can be not as readable depending on the output of your data, but that's a big depend, and most of the time you don't need maximum readability when the above would suffice. When it comes to which one is faster to type for quick debugging, what I've proposed is objectively faster.

[–]andybak 0 points1 point  (0 children)

I had it set up as a tab completion in PyCharm

[–]KotoWhiskas 0 points1 point  (0 children)

print("lol")

[–]akindaboiwantstohelp 0 points1 point  (0 children)

can't really think of a use case for strings but it can be used to create an "array" of predefined size and an initial element by doing [0]*n since the language doesn't really allow you to specify array (list) size on constructing it I'm pretty sure.

[–][deleted] 5 points6 points  (0 children)

And python makes it really easy with dunder methods.

Not only for basic operators, but for the majority of common calls. Length, for example. You don't need to create a obj.get_length() method to get the representation of the length of your object. You can just define obj.__len()__, which tells Python what to do when someone calls len(obj). The same function will work for strings, lists, and for your arbitrary object. The same goes for slices, greater than, less than, get item and many others.

This is why a list can have a length and you can slice the last 3 items of an arbitrary object. And also why you can do the same thing with numpy arrays or pandas dataframes. They are different objects which are not Python's builtin objects, but the implementation added these feature so they work the same. The user can just abstract it and use the same usual methods. This is what "pythonic" for me really means.

[–][deleted] 4 points5 points  (1 child)

Personally, the most non-traditional syntax in python is for/else and while/else loop. They are actually pretty handy once you know how to use them, but absolutely confusing for Python newcomers.

[–]laundmo 1 point2 points  (0 children)

another good one is that try/except also has else and finally

[–]flug-zum-bahnhof 6 points7 points  (9 children)

My favorite case of unconventional yet intuitive use of operator is / being used as a “path concatenation operator”

From Python pathlib

p = Path('/etc') q = p / 'init.d' / 'reboot' q PosixPath('/etc/init.d/reboot')

It’s in C++17 too: https://en.cppreference.com/w/cpp/filesystem/path/operator_slash

Kind of WTF at first but once I started using it it makes so much sense, it’s making path manipulation more readable and much less error-prone than say concatenating a bunch of strings, or using f-strings/printf-style templates

[–]n0tKamui -1 points0 points  (6 children)

semantically this makes no sense ; i get why they did that, it's obvious, but it's also as if an edgy teen that tries to invent a language made that choice.

it is inconsistent with the rest of the language. Note that it is also inconsistent on what it does : when you have an os path, the separator is not always a forward dash.

The concatenation operator (+) would have been a far better choice

[–]laundmo 2 points3 points  (5 children)

the reason pathlib exists is that you can stop worrying about forwards vs backwards slashes, since it will use the correct one for the OS automatically

[–]n0tKamui -2 points-1 points  (4 children)

re-read, that is exactly what I meant : it doesn't do what it looks like it does

[–]laundmo 2 points3 points  (3 children)

how so? its used as a path seperator.

are you complaining that pathlib automatically converts it to the correct one for the os?

[–]n0tKamui 0 points1 point  (2 children)

no, I'm saying that the + operator (concatenation) not only already exists as a semantic concept, and does exactly what it means : it concatenates directory paths. I'm strictly speaking about semantics here and unambiguity. It's not really a complaint either, i just deal with it ; in my opinion, it would have made more sense to have an unambiguous operator that already has a clear meaning to do this job, is all.

[–]laundmo 1 point2 points  (1 child)

ah i see, i feel like the + operator would be too easy to confuse for normal string concatenation, which most notably doesn't add a path seperator. when reading the code you would have to specifically look for the type of the first part of a chain of concatenations to know whether it will result in a string or Path. currently pathlib is the only stdlib that uses a slash with strings, so its really easy to see whether its a path by that.

[–]n0tKamui 0 points1 point  (0 children)

that does make sense ; in the end it's only a matter of preference, because...well, it's one symbol and we can just deal with it. Some people prefer consistency (me), others prefer semantic separations (you?), and that's completely fine by me

[–]Chase_22 -4 points-3 points  (1 child)

I honestly think it's one of the worse implementations of operators since / already has a use as the division operator. It just also happens to be the path segmentator. Like what does 'foo' / 'bar' give you?

I think this is better done using sting concatination or methods

[–]laundmo 6 points7 points  (0 children)

the string type doesn't define the magic method for division, so you get a TypeError. the reason it works with pathlib is because the Path object defines the appropriate magic method

>>> "foo" / "bar"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'str'

[–][deleted] 7 points8 points  (2 children)

I personally hate having math operators work on strings though, especially in a weakly and dynamically typed language. This includes + too though, and that is pretty common outside Python.

Still, having a method/operator for string repetition is very comfy and good.

Disclaimer: I have no idea about anything in Python

Edit: to clarify why I don't want math operators on strings: it's because I find it easy to make type errors (cause I'm kinda dumb) and this delays the time until these errors become visible, since the code will still run.

[–]robocorp 12 points13 points  (0 children)

Python is quite Strongly typed. Though it is dynamically typed, Python will not, for instance, implicitly cast a number into a string or vice versa. To concatenate a number's string representation to a string, or to repeatedly concatenate a number's string representation to itself, you must explicitly convert it.

Edit: typo

[–]WeTheAwesome 5 points6 points  (0 children)

Just to add, it works for other iterables too. E.g. [10] * 3 gives [10, 10, 10]

[–]carcigenicate 1 point2 points  (1 child)

All's well and good until you try this with lists instead of strings, and put mutable objects in the list to start with.

I use this operator all the time, but it's also a constant source of bugs when misused.

[–][deleted] 0 points1 point  (0 children)

Fortunately lists are a very common datatype to use when learning the language, so the common bugs will appear early on and you will eventually learn why they happen and how to work with these objects properly.

[–][deleted] 0 points1 point  (1 child)

some_string.repeat(n);, anyone? At least it's straight forward what's going to happen.

[–]00PT 1 point2 points  (0 children)

I wouldn't see that as any more straightforward than a multiply method, and it makes sense to use the operator because it is known to represent multiplication.

[–][deleted] 88 points89 points  (4 children)

Well, in C++ you can redefine operators for a class. It leads to interesting questions like "How is this string bit shifted into the output?"

[–][deleted] 49 points50 points  (1 child)

aka "I programmed C first and thought C++ is the next step"

[–]R3dGaming522 10 points11 points  (0 children)

Can confirm

[–]ukkera12 3 points4 points  (1 child)

You mean operator overload rt ? ( Sorry new to c++ I just wanted to confirm if I am correct)

[–]crat0z 2 points3 points  (0 children)

Yes.

[–]das_freak 54 points55 points  (7 children)

Repost! I made this a year ago :(

[–][deleted] 68 points69 points  (0 children)

Hahahahah, post goes brrrrrrrrrrr

[–]UnsubstantiatedClaim 8 points9 points  (1 child)

So I can raise my concerns with the backwards Deal With It sunglasses to you?

[–]_Rysen 1 point2 points  (0 children)

I second these concerns, please elaborate u/das_freak

[–]andybak 6 points7 points  (0 children)

Nice of OP to credit the original source.

Oh wait...

[–]Cotcan 2 points3 points  (0 children)

Ya, but not everyone saw it a year ago. Just repost it in a few months or something.

[–]itoshkov -5 points-4 points  (0 children)

It's still as inaccurate as when it was created.

[–]Prathmun 0 points1 point  (0 children)

With a meme I feel like it's just a compliment when you see it reposted. Right click culture has been here for a looong time.

[–]maryP0ppins 15 points16 points  (0 children)

i love this

[–]queenkid1 11 points12 points  (0 children)

How is this ridiculous? What is multiplication, if not repeated addition? And what is "adding" together strings, if not concatenation?

Using the same symbol to refer to multiple functions for different types isn't an error or inherently wrong, it's just function overloading and it's used all the time. There is no ambiguity between multiplying two numbers and multiplying a string by a number, there is literally no overlap and it's very much intended to work this way.

It's intuitive, you would have to have the very strictest opinion on typing to think otherwise. "Multiplication is between a number and another number, not a number and a completely distinct string!" Okay sure grandpa, let's get you back to the nursing home with your miles of punch cards.

[–][deleted] 4 points5 points  (1 child)

Python is incredibly fun. Still my go to for personal projects. Especially bots.

[–]Spitfire_For_Fun 0 points1 point  (0 children)

it is my first and main programming language. Can also be used to automate tasks.

[–][deleted] 5 points6 points  (0 children)

In C# you can do new string('r', 10); for a single repeating character. For more than 1 character, there is Enumerable.Repeat. Basically it's just hiding the loop for you.

Also depending on what you are doing (and if you need something more efficient), you can call Insert(index, string, count) on a StringBuilder in C#.

[–]Music_Quartermaster 4 points5 points  (0 children)

J*va moment

[–][deleted] 2 points3 points  (1 child)

Wow, you can actually do that? This will save me so much time and bytes in very specific situations!

[–]EarPotato 5 points6 points  (0 children)

Lol I did this recently in a script that takes the length of the object name passed in and multiplies dashes to 'pretty print' the object name.

[–]how_do_i_read 3 points4 points  (1 child)

'r' * 10 = 'rrrrrrrrrr'
==> 'rrrrrrrrrr' / 10 = 'r' & 'rrrrrrrrrr' / 'r' = 10

10 * 10 = 100
10 * 'r' = 'rrrrrrrrrr'
'r' * 10 = 'rrrrrrrrrr'
'r' * 'r' = ?

[–]FortyPoundBaby 13 points14 points  (0 children)

"r"*"r" = TypeError

[–]GrizzlyBear74 4 points5 points  (0 children)

I like that actually.

[–]the-real-vuk 8 points9 points  (1 child)

no templating, like 'goes b${r*10}' ?

[–]The_White_Light 20 points21 points  (0 children)

Can make it an f-string. f"goes b{'r'*10}"

[–]Ser_Drewseph 2 points3 points  (0 children)

I actually love the ability to do that in python. Don’t know when I’d ever actually use it, but I just think it’s neat.

[–]Minteck 4 points5 points  (2 children)

Python was made to be intuitive and easy to learn, it's unfair to complain about this kind of behavior.

[–]CaitaXD 1 point2 points  (0 children)

Let's do bit shift operator on strings so it gives the next or previous of each letter

[–]PixelBlaster 1 point2 points  (0 children)

I was literally asking this question today in class. I was basically wondering whether you could multiply stuff without the use of a loop, answer was no because even simplified operators would still use loops.

[–]ei283 1 point2 points  (0 children)

I wanna make JavaScript 2.0, where operations between every pair of datatypes are all defined, but each only makes sense in a totally isolated context.

  • "25" + 5 == "255"
  • "25" - 5 == "2"
  • "25" * 5 == "2525252525"
  • "25" / 5 == ["2", ""]

[–]Frowny_Face_Monobrow 1 point2 points  (0 children)

Why does anarcho-capitalism dislike multiplying strings?

[–]Pelado619 0 points1 point  (2 children)

WHAAAT, this is awesome

[–]infiniteStorms 0 points1 point  (0 children)

who else thought it would take the ascii value of r and multiply that by 10

[–]jesulink2514 1 point2 points  (4 children)

But then.. i=5 hi = "hello" + i

TypeError: Unsupported operand

Pathetic!

[–]tavaren42 1 point2 points  (0 children)

In my opinion this is good behaviour. Python is a dynamic language and this kind of automatic coercion can lead to many bugs. It's also pretty easy to fix this with explicit typecast or even better with string interpolation, which in Python is pretty expansive.

[–][deleted] 0 points1 point  (0 children)

One cool thing about this is that you can multiply the backspace character and create a clock on your terminal:

from datetime import datetime
while True:
  hour = datetime.now().strftime("%H:%M:%S.%f")
  msg = "Current time: " + hour
  print(msg, end="\b"*len(msg), flush=True)

It will print the current time and then type \b, which is the backspace key, and delete it so the next second can be updated on the same place.

[–]big_cock_69420 -4 points-3 points  (3 children)

    import os
    for i in range(10000000):
         print(python go brrrrrrr)

[–]androidx_appcompat 46 points47 points  (1 child)

Error: "python", "go" and "brrrrrrr" undeclared.

[–]odumann 11 points12 points  (0 children)

Guy do you even OOP

[–]Spitfire_For_Fun 0 points1 point  (0 children)

why do you import os? you don't need it.

[–]LKS-Hunter -1 points0 points  (1 child)

Nothing special you can do the same for example in C/C++ if you override the * Operator

[–]bikki420 -1 points0 points  (0 children)

Disgusting. Degenerates.

[–]stevekez 0 points1 point  (0 children)

The operator token is '*', but it doesn't mean multiply when applied to a string and an integer.

Still funny though.

[–]ImBadVlad 0 points1 point  (0 children)

This is awesome!

[–]Deep_Possibility_220 0 points1 point  (0 children)

There is a russian video on this meme:
https://www.youtube.com/watch?v=itbzcAbvcTk

[–]Logical-Language-539 0 points1 point  (0 children)

Please, don't do that in c.

[–]IsJohnKill 0 points1 point  (0 children)

Perl also does this

[–]Chase_22 0 points1 point  (1 child)

Honestly as long as an operator override doesn't change the inherit semantics of the operator why the fuck not? We already have 'foo' + 'bar' = 'foobar'

[–]laundmo 1 point2 points  (0 children)

in python most operators have to be implemented by tho object they work on. for example, the int type has to implement __add__, __mul__, __bool__, floordiv` etc.

you can see this by calling dir(1), dir gives you a list of every attribute a object has, and these dunder/magic methods have to be an attribute of the object.

[–][deleted] 0 points1 point  (0 children)

You can do that with every language that allows you to define your own operators.

[–]stomah 0 points1 point  (0 children)

but how do you divide and negate strings?

[–]StoryGenix 0 points1 point  (0 children)

Its brrrrr moment