DEV Community

loading...

Multiply a string? 🤔

Adam Crockett
I work at ForgeRock as Staff UI Engineer, I play with all sorts really. Lately WASM is my toy of interest.
・1 min read

Here's a simple thought, why can't you multiply, devide subtract a string?

In language design terms here's some examples.

"Hello world" * 2 // ["Hello world", "Hello world"];
"Hello world" - 3 // "Hello wo"
"Hello world" / 3 ["Hel", "lo ", "wor", "ld"];
Enter fullscreen mode Exit fullscreen mode

Umm yeah it's not so easy I suppose to handle remainders and it's a little confusing in some of the cases, what do you think?

Discussion (13)

Collapse
alohci profile image
Nicholas Stimpson

Are you familiar with languages that allow operator overloading? One big problem is achieving a common understanding of what an operator on a object means. For example, why is "Hello world" * 2 = ["Hello world", "Hello world"] and not "Hello worldHello world"?

Collapse
adam_cyclones profile image
Adam Crockett Author

As a JavaScript guy, we do have OO but its not well known and a bit of a hack. Although it looks cool, it's exotic, so I will never use the technique for fear of other developers scratching thier heads... That being said a plus operator against a string does have quite a bit of terrible type coercion potentials, all very confusing. I suppose the only way to avoid this is to have specifications, OO is not in the spec for JavaScript

Collapse
peerreynders profile image
peerreynders • Edited
  1. JavaScript is truly object-oriented - you can create "objects" directly without the help of constructor functions or classes. JavaScript doesn't implement class-based object orientation like mainstream OOP languages (which are essentially class-oriented). JavaScript classes are a template for creating objects. (Though in some ways JavaScript is also function-oriented)

  2. Function overloading isn't an OO feature. For example Erlang (a functional language) allows the reuse of a function name as long as the arity (number of accepted arguments) varies. And in C++ you can overload non-member functions so procedural code can use overloaded functions (same name but the parameter type signature varies). Operator overloading tends to be an extension of function overloading.

Thread Thread
adam_cyclones profile image
Adam Crockett Author

OO oporator overloading

Not OOP

dev.to/adam_cyclones/oporator-over...

Collapse
misobelica profile image
Mišo

In Python, you can do "string" * 3 but the result is "stringstringstring".

In Kotlin for example you can do extension function that overloads operator on string but I would not recommend it because it's not very intuitive.

Collapse
adam_cyclones profile image
Adam Crockett Author

That's cool, what about python integer multiply 🤔 maybe it's not such a crazy thought.

(I must learn kotlin soon)

Collapse
misobelica profile image
Mišo • Edited

While I sometimes use it in Python for delimiters in print("-" * 100) I don't think it's a big feature worth to spread. I think the method "*".repeat(100) would be more clear for people.

Collapse
debuqer profile image
Debuqer
"Hello world" * 2                 // ["Hello world", "Hello world"];
Enter fullscreen mode Exit fullscreen mode

so we have

["Hello world", "Hello world"] / 2           // "Hello world"
"Hello world" / 2              // ["Hello", "world"]
Enter fullscreen mode Exit fullscreen mode

so

["Hello world", "Hello world"]  / 4               
= "Hello world" / 2
= ["Hello", "world"]
Enter fullscreen mode Exit fullscreen mode

Ok Now lets multiply the result with 4 to see if we can get the the first value

["Hello", "world"] * 4 // is probably equals to
[["Hello", "world"], ["Hello", "world"], ["Hello", "world"], ["Hello", "world"]]
Enter fullscreen mode Exit fullscreen mode

Right?
Although I am not sure about what your new overloaded operation does, but the point is we can overload operators but first we need to know what that means. what does "*" really means for an array, or what are we talking about when we say "Hello world" can divide by 3.15?

Collapse
adam_cyclones profile image
Adam Crockett Author

My head, oh my head hurts 😂

Collapse
peerreynders profile image
peerreynders • Edited
let result;

result = Array.from({ length: 2 }, (_v) => 'Hello world'); // "Hello world" * 2
log();                                                     // ["Hello world", "Hello world"]
result = 'Hello world'.slice(0, -3);                       // "Hello world" - 3
log();                                                     // "Hello wo"
result = chunk('Hello world', 3);                          // "Hello world" / 3
log();                                                     // ["Hel", "lo ", "wor", "ld"]

function chunk(s, size) {
  const length = Math.ceil(s.length / size);
  const toChunk = (_v, i) => {
    const start = i * size;
    return s.slice(start, start + size);
  };
  return Array.from({ length }, toChunk);
}

function log() {
  console.log(result);
}
Enter fullscreen mode Exit fullscreen mode

So while the operator versions have brevity on their side I think they lack clarity, especially for those who are encountering this type of usage for the very first time. And in JavaScript the operators don't fit with the way type coercion is designed to work.

The solution to many problems is simply:

Just write a function

On a personal level I've never understood Haskell's obsession with "operators". "operators" don't add anything if they do exactly the same work as a function with one or two arguments - i.e. just stick to a function. The case is different if and only if not all arguments of the operator expression are evaluated, e.g. the conditional operator.

In many ways I prefer Erlang's philosophy:

This adheres to our general principle - we do not provide built-in mechanisms, we provide primitives with which mechanisms can be built

(Erlang provides the primitives, OTP implements the mechanisms)

i.e. let the language only supply the essential functionality needed to build everything else.

In the case of JavaScript it's a bit different as you are trying to delegate as much work as possible to the browser - the runtime can accomplish many natively implemented tasks much faster.

Collapse
adam_cyclones profile image
Adam Crockett Author

So before I start:

result = Array.from({ length: 2 }, (_v) => 'Hello world');

The callback is actually slower then map new Array(n). Completely irrelevant off topic stuff right here 😂

I take the point 💯 functional is clear and my thoughts ... Are usually a jumbled mess, non the less apparently Python can multiply a string so it must be a good idea, right? 🤷‍♂️

Collapse
ssimontis profile image
Scott Simontis

My immediate thought on multiplication was that the result should be "Hello worldHello world", I guess that is why :D

Collapse
adam_cyclones profile image
Adam Crockett Author

Exactly so, it's so open to interpretation that it can't be implemented successfuly... Except apparently python can do it 😂