Text.replace() producing unexpected results

I’m trying to replace substrings within a string. I expect the following Motoko statement:

Text.replace("123", #text("124"), "ABC");

To behave just like this Javascript statement:

"123".replace("124", "ABC");

That is, I expect the input to be returned unchanged since there are no matches for "124. I expect to get “123”.

Instead, I get “12”. This doesn’t make any sense to me and seems like a bug. Why did it chop the “3” off the end of the input string when it didn’t find a match?

Further, I expected this statement to work:

Text.replace("123", "124", "ABC")

But that gives me the following error:

literal of type Text does not have expected type
  {#char : Char; #predicate : Char -> Bool; #text : Text}

So I changed "124" to #text("124"). Seems like Motoko could probably have figured out what I meant there, given that what I provided was a Text, and not a Char or function. But this probably hints to a misunderstanding that I have about how to use Text.Pattern correctly, which is probably why my Text.replace call isn’t working as I expect.

What am I missing here?

The behaviour of replace seems like a bug - thanks for reporting it! I’ll investigate.

Preferring safety over convenience, Motoko does not do implicit conversions of values (as you might expect from JS).

The second argument to replace has a variant type (the pattern), so you do need to supply one of the variants, or a value of a subtype, as the argument. Here, the variant tag #text cannot be omitted: even though unambiguous in this particular example, it wouldn’t be in many other cases.

https://github.com/dfinity/motoko-base/issues/234

2 Likes

Thanks for the quick fix, @claudio! I saw that it was merged to master yesterday. Out of curiosity, how long does it take for such a change to show up on the ic network? And if I wanted to get these changes locally, is it just a matter of running dfx upgrade? I imagine that doesn’t pull from master directly, and I’ll need to wait for a deploy.

These questions are mere curiosity; this change isn’t holding up progress or anything.

It will hopefully be included in the next release of dfx, as part of the Motoko it bundles, unless we miss that train.

For now, you could probably just download the file and either copy it over where ever dfx has installed Text.mo, as a stop-gap measure, or just make a local copy and import it as a library, repointing its own imports to base.

And thanks again for the bug report - that was a pretty nasty bug (my bad too).

If you’re using vessel to manage your Motoko dependencies, you can get it right away. Just add an override to the package-set.dhall file referencing the commit with the fix, something like this:

let upstream =
      https://github.com/dfinity/vessel-package-set/releases/download/mo-0.5.10-20200309/package-set.dhall sha256:666baf38b183ff0d0f9bed339701a85bc4028d23e2af713c9c68fd999ad418a3

let overrides = [ 
  { name = "base"
  , version = "84e9a45347e6bae4ef02d478cc39f6dd438080ad"
  , repo = "https://github.com/dfinity/motoko-base"
  , dependencies = [] : List Text
  }
] 
in upstream # overrides
2 Likes

(I missed the train, don’t expect the fix with dfx 0.6.26)