# X-expression string length

**URL:** <https://racket.discourse.group/t/x-expression-string-length/550>\
**Category:** Questions & Answers\
**Created:** [January 11, 2022, 3:57pm UTC](https://racket.discourse.group/t/x-expression-string-length/550 "2022-01-11T15:57:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![joeld](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/joeld/32/38_2.png) [@joeld](https://racket.discourse.group/u/joeld)\
**Post date:** [January 11, 2022, 3:57pm UTC](https://racket.discourse.group/t/x-expression-string-length/550/1 "2022-01-11T15:57:08Z")

</div>

I thought I would try and calculate the length of an X-expression's string representation without actually converting the whole thing to a string. I theorized that if I could do it with math and immutable strings, it would be faster. But it turned out to be three times slower! [**edit:** I removed all uses of `match`-like forms and got it down to a roughly 2x difference]

> <https://gist.github.com/otherjoel/277cb0a76474a579e9aba95d0d6284fb>

I’m curious if anyone has any insight as to why this is. Am I holding it wrong, or is `(string-length (xexpr->string x))` just the fastest method?

The use-case is I have large x-expressions that I need to cleanly break up into chunks no larger than 5000 characters when converted to strings in order to fit under and API limit.

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [January 11, 2022, 4:48pm UTC](https://racket.discourse.group/t/x-expression-string-length/550/2 "2022-01-11T16:48:41Z")

</div>

[`txexpr->value`](https://github.com/mbutterick/txexpr/blob/master/txexpr/base.rkt#L156)‘s implementation uses `txexpr?` to decide how it should parse the datum, where `txexpr?` needs to handle a lot of cases.

But if we assume that `txexpr->value`‘s input is a `txexpr?`, then there are many cases that we don’t need to check, allowing us to specialize/simplify the code significantly.

If you use the following version instead:

```scheme
(define (txexpr->values x)
  (match x
    [(list tag (? list? attrs) children ...)
     (values tag attrs children)]
    [(list tag children ...)
     (values tag '() children)]))

```

it should be faster than the `xexpr->string` version.

---

<div class="post-metadata">

**Author:** ![joeld](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/joeld/32/38_2.png) [@joeld](https://racket.discourse.group/u/joeld)\
**Post date:** [January 11, 2022, 5:00pm UTC](https://racket.discourse.group/t/x-expression-string-length/550/3 "2022-01-11T17:00:04Z")

</div>

[That did it](https://gist.github.com/otherjoel/277cb0a76474a579e9aba95d0d6284fb/revisions), this method is now about 5 times faster. Thanks!

Yes, it makes sense that any use of `txexpr?` slows things dow a lot, because it has to walk down the entire x-expression every time to verify it, and because of the `map` here it ends up being called several times for the same values.

---

<div class="post-metadata">

**Author:** ![ryanc](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/ryanc/32/71_2.png) [@ryanc](https://racket.discourse.group/u/ryanc)\
**Post date:** [January 11, 2022, 6:11pm UTC](https://racket.discourse.group/t/x-expression-string-length/550/4 "2022-01-11T18:11:28Z")

</div>

Beware, the `string?` case doesn't account for entity-escaping characters like `<`.

---

<div class="post-metadata">

**Author:** ![joeld](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/joeld/32/38_2.png) [@joeld](https://racket.discourse.group/u/joeld)\
**Post date:** [January 11, 2022, 11:22pm UTC](https://racket.discourse.group/t/x-expression-string-length/550/5 "2022-01-11T23:22:56Z")

</div>

Good point. I think the only ones I’d need to look for are `<`, `>`, and `&`.
