# String.from()

**URL:** <https://es.discourse.group/t/string-from/2252>\
**Category:** 💡 Ideas\
**Created:** [December 19, 2024, 2:23pm UTC](https://es.discourse.group/t/string-from/2252 "2024-12-19T14:23:42Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![martinheidegger](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/martinheidegger/32/2247_2.png) [@martinheidegger](https://es.discourse.group/u/martinheidegger)\
**Post date:** [December 19, 2024, 2:23pm UTC](https://es.discourse.group/t/string-from/2252/1 "2024-12-19T14:23:42Z")

</div>

Now that we have `.from()` on `Array`, `TypedArrays` and `Iterator` it would seem logical to also have it on `String`.

Example:

```javascript
String.from(function *() { yield 'a'; yield 'b' })` // "ab"

```

or

```javascript
String.from({ length: 2 }, () => 'x')` // `"xx"`

```

I could even imagine something like:

```javascript
String.from([65, 66]) // AB

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 19, 2024, 6:09pm UTC](https://es.discourse.group/t/string-from/2252/2 "2024-12-19T18:09:28Z")

</div>

What problems would this solve?

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [December 19, 2024, 9:08pm UTC](https://es.discourse.group/t/string-from/2252/3 "2024-12-19T21:08:28Z")

</div>

> [@martinheidegger](#):
>
> `String.from([65, 66]) // AB`

You can do something similar today with fromCharCode

```javascript
String.fromCharCode(...[65, 66]) // "AB"

```

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [December 19, 2024, 10:43pm UTC](https://es.discourse.group/t/string-from/2252/4 "2024-12-19T22:43:50Z")

</div>

I've always thought this was an obvious API to provide. I've written the implementation by hand maybe 10-20 times by now, and I'm still not sure if I'm doing it "right" from the perspective of perf. I'd much rather just focus on providing the iterable of characters and let the engine implementer decide what the best perf approach is for allocating out the string.

---

<div class="post-metadata">

**Author:** ![martinheidegger](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/martinheidegger/32/2247_2.png) [@martinheidegger](https://es.discourse.group/u/martinheidegger)\
**Post date:** [December 19, 2024, 11:18pm UTC](https://es.discourse.group/t/string-from/2252/5 "2024-12-19T23:18:44Z")

</div>

> [@ljharb](#):
>
> What problems would this solve?

Mostly API consistency: People learning about `.from` noticing that `String.from` is a bit more complicated for no apparent. Reason.

```javascript
const bytes = Uint8Array.from([65, 66])
const str = String.from(bytes)

```

My assumption would also be that it could be easy to improve the performance of this API (conversion of Uint8 → string).

```javascript
String.fromCharCode(...[65, 66]) // "AB"

```

Unlike the current `String.fromCharCode` (thanks for mentioning it @senocular) there is no destructuring statement necessary to use `String.from` which should work in favor of speed.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 20, 2024, 1:28am UTC](https://es.discourse.group/t/string-from/2252/6 "2024-12-20T01:28:12Z")

</div>

Can you elaborate on a concrete use case or application where the speed of concatenating strings from an iterable (as opposed to from an array) is important?

---

<div class="post-metadata">

**Author:** ![martinheidegger](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/martinheidegger/32/2247_2.png) [@martinheidegger](https://es.discourse.group/u/martinheidegger)\
**Post date:** [December 20, 2024, 3:30am UTC](https://es.discourse.group/t/string-from/2252/7 "2024-12-20T03:30:50Z")

</div>

Concatenating from an iterable is for writing comfort, . `String.from(Iterator.range(65, 90))` in mind.

The performance aspect would be mostly in comparison to `String.fromCharCode()`. The existing one uses a list of arguments that is surely harder to optimize than a function call with the byte buffer directly passed to it. In comparison to `(new TextDecoder()).decode(bytes)` it is probably similar, but since `String.from` is so much more accessible, my thinking is that is probably going to be a preferred API.

Particularly for the performance-relevant `TextDecoderStream`, the following API - in an amendment to the initial idea - could be quite appealing.

```javascript
await String.fromAsync(bytesStream)

```

instead of what I can gather is the fastest way to do that;

```javascript
(await Array.fromAsync(bytesStream.pipeThrough(new TextDecoderStream())).join('')

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 20, 2024, 6:05am UTC](https://es.discourse.group/t/string-from/2252/8 "2024-12-20T06:05:26Z")

</div>

`String.fromCharCode(...Iterator.range(65, 90))` seems equally comfortable to me?

---

<div class="post-metadata">

**Author:** ![martinheidegger](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/martinheidegger/32/2247_2.png) [@martinheidegger](https://es.discourse.group/u/martinheidegger)\
**Post date:** [December 20, 2024, 7:53am UTC](https://es.discourse.group/t/string-from/2252/9 "2024-12-20T07:53:22Z")

</div>

It is odd to me that you think it is _ **equally** _ comfortable.

- `String.fromCharCode(...X)` is simply more to type than `String.from(X)`.
- `String.fromCharCode` is different from `Array.from` and `Iterator.from` which means one needs to remember this exception. _(mental load)_
- `fromCharCode` suggests from a single character and not multiple, you'd have to read the signature to figure that out that it supports the `fromCharCode(...)` use.
- Users don't learn all concepts at once. Some people might be familiar with `Array.from(...)` before learning about `...` operator: they need to Learn (...) before they understand how to use this API.
- `fromCharCode` does not support the second parameter `String.from(input, mapFunction)` which can come in handy at times.

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [December 21, 2024, 5:01am UTC](https://es.discourse.group/t/string-from/2252/10 "2024-12-21T05:01:05Z")

</div>

In my daily programming, I barely need to concat strings from an iterator. I sometimes need to create a string from an array, in this case I will use array.join.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [December 22, 2024, 5:27pm UTC](https://es.discourse.group/t/string-from/2252/11 "2024-12-22T17:27:33Z")

</div>

My understanding of the way `...` in args works is that it takes a lazy data source and first makes it unlazy, i.e. allocates it. In this case it would have to allocate the structure into an array I think (any attempt to omit this step would change behavior), and only then once you'd make the complete array would you be able to throw that array out, using it as kind of temporary iterator for building the real allocation structure, the string. Why are we making an array to use as an iterator later when we have an iterator already right now?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 22, 2024, 10:19pm UTC](https://es.discourse.group/t/string-from/2252/12 "2024-12-22T22:19:01Z")

</div>

That's a fair point if you're talking about a large number of graphemes or code points or code units, but on the scale of, like, "less than 5-6 zeros worth", I doubt the cost of a temporary array will even be noticeable (and if you're performance-sensitive you'd want to avoid the iterator protocol entirely anyways)

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [December 22, 2024, 10:42pm UTC](https://es.discourse.group/t/string-from/2252/13 "2024-12-22T22:42:27Z")

</div>

But this is at its core a matter of consistency more than it is a matter of perf. All these other APIs like `Map` constructor take iterables, and as far as I can tell if your argument were pervasively convincing they would only take arrays...

Now, that said, I'm in agreement that without a real use case this shouldn't go into the language.

The real use case I see is file streaming, but unfortunately sync iterators of characters don't allow for any asynchronicity while async iterators have too much overhead to step character-by-character. So in effect I guess with the state of the language as it is I am forced to agree with Jordan. Short of providing support for an iterable protocol performant enough to carry character streams, there would be little point in doing this
