# Syntaxic sugar: String.set -\> Bytes.set?

**URL:** <https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275>\
**Category:** Learning\
**Tags:** evolution\
**Created:** [August 8, 2022, 9:00am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275 "2022-08-08T09:00:23Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![fccm](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/fccm/32/1587_2.png) [@fccm](https://discuss.ocaml.org/u/fccm)\
**Post date:** [August 8, 2022, 9:00am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/1 "2022-08-08T09:00:23Z")

</div>

```auto
$ cat s.ml

let () =
  let s = Bytes.of_string "Hello" in
  s.[4] <- 'a';
  print_endline (Bytes.to_string s)

$ ocaml s.ml
File "./s.ml", line 4, characters 2-14:
4 | s.[4] <- 'a';
      ^^^^^^^^^^^^
Alert deprecated: Stdlib.String.set
Use Bytes.set/BytesLabels.set instead.
Hella

```

I was trying to figure out how to update my scripts that are using this syntaxic sugar?  
Is it planed to be replaced by `Bytes.set` in the next release?  
How can I already make this syntaxic sugar point to `Bytes.set` with 4.14 in a forward compatible way?  
Or is this syntaxic sugar just planed to disappear?

---

<div class="post-metadata">

**Author:** ![raphael-proust](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/raphael-proust/32/415_2.png) [@raphael-proust](https://discuss.ocaml.org/u/raphael-proust)\
**Post date:** [August 8, 2022, 9:17am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/2 "2022-08-08T09:17:30Z")

</div>

It doesn’t answer your question directly (I don’t know where the Stdlib is going w.r.t. Bytes/String and syntactic sugar), but something that might help is that you can use

```auto
let ( .%[]<- ) = Bytes.set

```

and then

```auto
  s.%[4] <- 'a';

```

---

<div class="post-metadata">

**Author:** ![bcc32](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/bcc32/32/203_2.png) [@bcc32](https://discuss.ocaml.org/u/bcc32)\
**Post date:** [August 8, 2022, 1:57pm UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/3 "2022-08-08T13:57:03Z")

</div>

BTW, `.[] <-` syntax has been removed in [Remove (.[]\<-) by nojb · Pull Request #11345 · ocaml/ocaml · GitHub](https://github.com/ocaml/ocaml/pull/11345), so it will be gone in 5.0 I think.

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [August 8, 2022, 2:19pm UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/4 "2022-08-08T14:19:18Z")

</div>

Removed as in, removed from just the `String` module or removed as in no longer valid OCaml syntax?

---

<div class="post-metadata">

**Author:** ![bcc32](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/bcc32/32/203_2.png) [@bcc32](https://discuss.ocaml.org/u/bcc32)\
**Post date:** [August 8, 2022, 2:32pm UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/5 "2022-08-08T14:32:50Z")

</div>

As I understand it, the syntax itself has been removed. So the old trick of “module String = Bytes” doesn’t work either.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [August 9, 2022, 6:28am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/6 "2022-08-09T06:28:38Z")

</div>

> [@yawaramin](#):
>
> Removed as in, removed from just the `String` module or removed as in no longer valid OCaml syntax?

The syntax has been removed from OCaml 5.0 altogether. The reason is that `s.[i] <- c` was an alias for `String.set` which was also removed. It was briefly discussed to make `s.[i] <- c` an alias for `Bytes.set` but it was concluded that this would be weird, since `s.[i]` continues to be an alias for `String.get`.

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![hyphenrf](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hyphenrf/32/2733_2.png) [@hyphenrf](https://discuss.ocaml.org/u/hyphenrf)\
**Post date:** [August 10, 2022, 12:25am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/7 "2022-08-10T00:25:16Z")

</div>

reminder that custom indexing operators incur some overhead and aren’t as inliner-happy as the pure syntax sugar of `Array` and `String`. reminder that `-unsafe` doesn’t work with custom indexing operators.

---

<div class="post-metadata">

**Author:** ![octachron](https://avatars.discourse-cdn.com/v4/letter/o/49beb7/32.png) [@octachron](https://discuss.ocaml.org/u/octachron)\
**Post date:** [August 10, 2022, 6:57am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/8 "2022-08-10T06:57:25Z")

</div>

> [@hyphenrf](#):
>
> reminder that custom indexing operators incur some overhead and aren’t as inliner-happy as the pure syntax sugar of `Array` and `String`.

That’s false since the custom indexing operators are functions, and thus they are obviously equivalent to the desugaring of `a.(x)` to `Array.get a x`. In other words, there are no difference between

```ocaml
external get : 'a array -> int -> 'a = "%array_safe_get"

```

and

```auto
external (.%()): : 'a array -> int -> 'a = "%array_safe_get"

```

> [@hyphenrf](#):
>
> reminder that `-unsafe` doesn’t work with custom indexing operators.

I would say this is a feature, since `-unsafe` is a syntactic flag, that makes `a.(x)` desugars to `Array.unsage_get a x` . And it is possible to define unsafe custom operators if you need them.

---

<div class="post-metadata">

**Author:** ![hyphenrf](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hyphenrf/32/2733_2.png) [@hyphenrf](https://discuss.ocaml.org/u/hyphenrf)\
**Post date:** [August 10, 2022, 11:45pm UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/9 "2022-08-10T23:45:57Z")

</div>

> That’s false since the custom indexing operators are functions

went off with that claim based on stuff like this: [Compiler Explorer](https://godbolt.org/z/3YszMabbq)

the `.%()` is `call`ed with the target subroutine being a whole bunch of instructions, still polymorphic, etc… while `.()` is just a `cmp` + `mov` and not polymorphic (according to lambda `array.get[addr] ...`).

It seems there’s no difference between two definitions of the same `external` function, but there is a difference when aliasing them at the ocaml level.  
I may be reading this wrong though, but I guess I never expected needing to reach out for `external` compiler builtins for a harmless change like using a custom operator instead of the normal one, to get back that performance loss.

---

<div class="post-metadata">

**Author:** ![fccm](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/fccm/32/1587_2.png) [@fccm](https://discuss.ocaml.org/u/fccm)\
**Post date:** [August 11, 2022, 10:18am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/10 "2022-08-11T10:18:40Z")

</div>

Hi Nicolas,

> [@nojb](#):
>
> The syntax has been removed from OCaml 5.0 altogether. The reason is that `s.[i] <- c` was an alias for `String.set` which was also removed.

For me `String.set` was not removed, but moved to the `Bytes` module as `Bytes.set`.  
So it was logic for me to expect that `s.[i] <- c` would work with the `bytes` type.  
What other people here think about it?

> [@nojb](#):
>
> It was briefly discussed […]

If it was only briefly discussed, maybe we could try to make it here and now, and ask opinions about it?

> [@nojb](#):
>
> It was briefly discussed to make `s.[i] <- c` an alias for `Bytes.set` but it was concluded that this would be weird, since `s.[i]` continues to be an alias for `String.get`.

I do agree that it is weird. But I think it is even much more weird if it’s just removed.

Also to update current code, I only need to add `bytes.to/of_tring` which is usually not that bad.

Rewriting all the `s.[i] <- c` everywhere with `Bytes.set` is more time consuming (but I didn’t know I can also just add a ‘%’ in the middle, so it’s not that bad with this solution.)

This is what the error/warning message tells us to do, using `Bytes.set`, the error message could tell about the custom `s.%[i] <- c` possible replacement. This could have make me save time, it’s maybe not too late for 5.0.

> [@nojb](#):
>
> […] since `s.[i]` continues to be an alias for `String.get`.

I had some hope that `s.[i]` would work with both `string` and `bytes` types, just like `>` works with both `int` and `float`. There is no need to use `>.` with `floats`.

We could also imagine something like:

```auto
  Bytes.( s.[i] );
  String.( s.[i] );

```

---

<div class="post-metadata">

**Author:** ![bluddy](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/bluddy/32/104_2.png) [@bluddy](https://discuss.ocaml.org/u/bluddy)\
**Post date:** [August 11, 2022, 11:04am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/11 "2022-08-11T11:04:16Z")

</div>

If we’re talking about expectations, I would have loved `[]` to be removed from String and shifted to either Array instead of `.()` or a new Vector type, where it would fit the expectations of the user.

---

<div class="post-metadata">

**Author:** ![hyphenrf](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hyphenrf/32/2733_2.png) [@hyphenrf](https://discuss.ocaml.org/u/hyphenrf)\
**Post date:** [August 12, 2022, 12:17am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/12 "2022-08-12T00:17:14Z")

</div>

yeah string should just not have indexing sugar, it encourages treating strings as readonly byte arrays and proliferate the whole byte = char = grapheme misconception.

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [August 12, 2022, 12:34am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/13 "2022-08-12T00:34:53Z")

</div>

Can’t custom string operators be defined to work on graphemes?

---

<div class="post-metadata">

**Author:** ![jumpnbrownweasel](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/jumpnbrownweasel/32/3062_2.png) [@jumpnbrownweasel](https://discuss.ocaml.org/u/jumpnbrownweasel)\
**Post date:** [August 12, 2022, 3:02am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/14 "2022-08-12T03:02:34Z")

</div>

this would be very inefficient with utf8 (it would have to walk the string from the start) so i wonder if indexing-like syntax would be misleading

---

<div class="post-metadata">

**Author:** ![yawaramin](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/yawaramin/32/3384_2.png) [@yawaramin](https://discuss.ocaml.org/u/yawaramin)\
**Post date:** [August 12, 2022, 5:16am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/15 "2022-08-12T05:16:06Z")

</div>

Then we are back to square one if it turns out that everyone really just wants to be able to index into specific bytes in strings and not graphemes.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [August 12, 2022, 6:30am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/16 "2022-08-12T06:30:51Z")

</div>

> [@fccm](#):
>
> If it was only briefly discussed, maybe we could try to make it here and now, and ask opinions about it?

It was only briefly discussed because there was quick consensus on removing the syntax, see ["str.[i] \<- c" is desugared into "String.set str i c" which does not exist anymore · Issue #11342 · ocaml/ocaml · GitHub](https://github.com/ocaml/ocaml/issues/11342)

> [@fccm](#):
>
> But I think it is even much more weird if it’s just removed.

The syntax `s.[i] <- c` (aka `String.set`) has been deprecated since 4.02 so codebases should have had plenty of time to adapt.

> [@fccm](#):
>
> I had some hope that `s.[i]` would work with both `string` and `bytes` types, just like `>` works with both `int` and `float`. There is no need to use `>.` with `floats`.

OCaml does not support operator overloading. The comparison with `>` is not a good one, because this operation is parametrically polymorphic and can be applied to arguments of any type. The right comparison would be with addition (`+`, `+.`), which indeed uses different operators for `int` and `float`.

> [@fccm](#):
>
> We could also imagine something like:
> 
> ```auto
> Bytes.( s.[i] );
> String.( s.[i] );
> 
> ```

This is an interesting proposal (and has been discussed in the context of `array` and `floatarray`), but this requires designing a new language feature. RFC/PRs welcome 🙂

Cheers,  
Nicolas

---

<div class="post-metadata">

**Author:** ![thierry-martinez](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thierry-martinez/32/1481_2.png) [@thierry-martinez](https://discuss.ocaml.org/u/thierry-martinez)\
**Post date:** [August 12, 2022, 1:43pm UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/17 "2022-08-12T13:43:33Z")

</div>

> [@nojb](#):
>
> This is an interesting proposal (and has been discussed in the context of `array` and `floatarray`), but this requires designing a new language feature. RFC/PRs welcome 🙂

Don’t we already have this? 😉

```auto
module Bytes = struct
  include Bytes

  module String = struct
    let get = get
  end
end

module String = struct
  include String

  module String = struct
    let get = get
  end
end

let s : string = "Hello, world!"

let () = assert String.(s.[0] = 'H')

let b : bytes = Bytes.of_string "Hello, world!"

let () = assert Bytes.(b.[0] = 'H')

```

---

<div class="post-metadata">

**Author:** ![hyphenrf](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hyphenrf/32/2733_2.png) [@hyphenrf](https://discuss.ocaml.org/u/hyphenrf)\
**Post date:** [August 13, 2022, 2:59am UTC](https://discuss.ocaml.org/t/syntaxic-sugar-string-set-bytes-set/10275/18 "2022-08-13T02:59:01Z")

</div>

Amusingly this also works with any module named Array in context:

```ocaml
module Array = Bytes
let s = Bytes.of_string "test"
let _ = s.(0) <- 'r'; print_char s.(1)

```
