# String is a Class, why?

**URL:** <https://forum.crystal-lang.org/t/string-is-a-class-why/5148>\
**Category:** Help & Support\
**Created:** [December 3, 2022, 7:16pm UTC](https://forum.crystal-lang.org/t/string-is-a-class-why/5148 "2022-12-03T19:16:24Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![MistressRemilia](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/mistressremilia/32/2585_2.png) [@MistressRemilia](https://forum.crystal-lang.org/u/MistressRemilia)\
**Post date:** [December 3, 2022, 7:16pm UTC](https://forum.crystal-lang.org/t/string-is-a-class-why/5148/1 "2022-12-03T19:16:24Z")

</div>

This is just out of curiosity, and came up when a friend asked why `String`s are a Class in Crystal instead of a Struct.

Unless I’m missing something, the `String` class is essentially a wrapper around a `Pointer(UInt8)` in memory, where the first 12 bytes is a header (a type ID, size in bytes, and size in code points). The `#to_unsafe` method returns a pointer to the data that exists after this small header. Is this all correct? If so, why isn’t `String` a struct since the underlying data is just a pointer?

I did some searching both here and on Google and didn’t find anything that quite answered my question, though I did find this [older post](https://forum.crystal-lang.org/t/why-arent-strings-pooled/2749) that shed a bit of light onto things. Same thing, “do things the simple and dumb way” to avoid GC issues with certain cases?

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [December 3, 2022, 9:50pm UTC](https://forum.crystal-lang.org/t/string-is-a-class-why/5148/2 "2022-12-03T21:50:59Z")

</div>

> [@MistressRemilia](#):
>
> the `String` class is essentially a wrapper around a `Pointer(UInt8)` in memory, where the first 12 bytes is a header (a type ID, size in bytes, and size in code points).

Nope, `String` does not have a pointer. The string data is actually directly embedded.

The memory layout of a string looks like this:

```crystal
slice = Bytes.new("foo".unsafe_as(Pointer(UInt8)), 16) 
slice # => Bytes[1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 102, 111, 111, 0]
      # ^^TYPE_ID^ ^bytesize^ ^charsize^ 'f' 'o' 'o' \0

```

Every reference type has the `TYPE_ID` as first field. Then the `bytesize` and `charsize` fields are also pretty standard. But they’re immediately followed by the payload, the string content. This is not an additional pointer to somewhere else.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [December 3, 2022, 10:18pm UTC](https://forum.crystal-lang.org/t/string-is-a-class-why/5148/3 "2022-12-03T22:18:41Z")

</div>

However, if you inspect the instance variables of a string, for example using tool hierarchy, you’ll see that the last member of a string is a char, not a pointer. That’s the first char of the string, then a pointer to that would give you the entire data (which is how to\_unsafe is implemented)

It’s a little trick. I think C# does the same thing, not sure.

---

<div class="post-metadata">

**Author:** ![MistressRemilia](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/mistressremilia/32/2585_2.png) [@MistressRemilia](https://forum.crystal-lang.org/u/MistressRemilia)\
**Post date:** [December 3, 2022, 11:34pm UTC](https://forum.crystal-lang.org/t/string-is-a-class-why/5148/4 "2022-12-03T23:34:21Z")

</div>

Gotcha, thank you! I must have misread the code earlier. I see how it’s being implemented now.

So is it a class instead of a struct for reasons similar to what was mentioned in the other thread I linked? Reading a huge file into a string onto the stack sounds like it would be inefficient to pass around.
