Read and write a temporary file
This application recipe uses the real Go os package without a wrapper runtime. Every fallible operation remains visible, and temporary resources are cleaned on success or early return.
Source
import go fmt from "fmt";
import go os from "os";
function writeAndRead(text: string): Result<string> {
const file = os.CreateTemp("", "kinmokusei-docs-*")?;
const path = file.Name();
defer os.Remove(path);
defer file.Close();
const written = file.WriteString(text)?;
if (written !== len(text)) {
return fail(fmt.Errorf("short write: %d of %d bytes", written, len(text)));
}
const contents = os.ReadFile(path)?;
return string(contents);
}
function main(): void {
const [contents, err] = writeAndRead("steaming");
if (err !== nil) {
fmt.Println("error:", err.Error());
return;
}
fmt.Println(contents);
}Run
keika check filesystem-round-trip.km
keika run filesystem-round-trip.kmExpected output:
steamingThe temporary path is intentionally absent from the output, so the example has the same observable contract on every supported platform.
Follow the failure path
os.CreateTemp, WriteString, and os.ReadFile return Go errors. Postfix ? handles both (T, error) shapes:
- evaluate the call once;
- return the result type's zero value plus the error when it is non-nil;
- otherwise yield
Tto the binding.
WriteString reports a byte count, so the function also rejects a short write even when the returned error is nil. len(text) is correct here because file writes count raw bytes, not Unicode code points, regardless of UTF-8 validity.
At the call site, [contents, err] exposes the generated Go (string, error) boundary. The non-nil branch returns before err.Error() can be called with a nil receiver.
Cleanup order
Deferred-call arguments are captured when each defer statement executes. Calls run in last-in, first-out order when writeAndRead returns:
defer os.Remove(path); // runs second
defer file.Close(); // runs firstClosing before removal makes the example portable to platforms that do not permit deleting an open file. This concise form intentionally ignores cleanup errors. Code that must report a close failure should close explicitly on the success path while retaining a deferred fallback for earlier returns.
Use Errors, Result, and exceptions for propagation semantics and Go interoperability for imported pointers, methods, and raw errors.