From text to number, and back
toInt raises a ParseError when the text is not a number, toText returns a str you can still work on.
A text that looks like a number is not a number: "3" * 2 means nothing, and the compiler says
so. The crossing is asked for, in either direction — and one of the two can fail.
import { StrText } from "std/extensions/str-text.arc";
import { IntText } from "std/extensions/int-text.arc";
extend archetype str StrText;
extend archetype int IntText;
@entry(start)
object MyProgram {
start() {
var measure := "3";
var doses := measure.toInt();
Console.print(text: $"twice as much: {doses * 2}");
Console.print(text: $"in the ledger: [{doses.toText().alignedRight(width: 4)}]");
try {
var wrong := "three".toInt();
Console.print(text: $"never reached: {wrong}");
} catch (raised: ParseError) {
Console.print(text: $"refused: {raised.message}");
}
}
}
Two files, two extends
import { StrText } from "std/extensions/str-text.arc";
import { IntText } from "std/extensions/int-text.arc";
extend archetype str StrText;
extend archetype int IntText;
toInt is a method of str, toText a method of int: two different types, so two
bundles, so two lines each. The headers grow longer, and that is the price of a tiny core: what
the program uses, it names.
toInt can fail, so it raises
"three".toInt() does not return zero, does not return some default: it raises a
ParseError.
refused: 'three' is not a valid integer
It is the reasoning of 8.2 applied once more: a text explicitly asked to be a number, and which
is not one, is a genuine error — not an absence to be marked with a zero, since zero would be a
perfectly plausible number and nothing would tell it apart from a successful "0".
Hence the try / catch around the call, written exactly as in 8.1, with an error archetype
supplied by the language.
toText, when interpolation is no longer enough
Interpolation already converts: $"{doses}" prints 3 without being asked. So why toText?
Because interpolation returns a finished text, and toText a str you can still work on:
doses.toText().alignedRight(width: 4)
alignedRight pads on the left up to the requested width — enough to line numbers up in a
column. It comes from StrText, like everything else in 9.1: once toText has returned a
str, that text can do everything a str can do.
What interpolation does not convert
Four types go into a $"…" hole: int and its widths, float, bool and str. An archetype
of yours is not among them, and the refusal is explicit:
error[T032]: an interpolated hole of type 'Potion' has no text conversion: only 'int' and its
widths, 'float', 'bool' and 'str' convert -- give the value a 'str' first
“Give the value a str first”: a method of yours, on your archetype, returning the text you
want to see. The language does not guess what a written potion looks like.
The rest of the library, in the same place
Same mechanism, other files:
toFloat()on astr—StrReal, instd/extensions/str-real.arc;squareRoot()andfloored()on afloat64—FloatMath, instd/extensions/float-math.arc;toText()for afloat64or abool—FloatTextandBoolText, each in its own.
Over to you
- Give
"3 doses"totoInt: the text is not a whole number, soParseError. It has to be cut first — 9.2 showed how. - Remove the
try/catchand let the error through: the program stops and names it, as in 8.2. - Set
measureto"1234"keepingwidth: 4, thenwidth: 2: a text longer than the requested width is not clipped, it comes out as it is. - Catch the
ParseErrorand return0instead: that is your decision to treat the absence that way, taken knowingly, and not the language’s taken for you.