Namespace duplication & conflicts: System.* overlaps Os.* (arg/arg_count/env/exit + streams); consolidate #40
Labels
No labels
area:ci
area:docs
area:input
area:net
area:rendering
area:repo
area:stdlib
area:tooling
area:types
cleanup
dx
priority:high
priority:low
priority:medium
proposal
status:in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: workshopsoft/ludic#40
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
System.*andOs.*are two public, documented namespaces that cover the sameconcern — the process/environment around the game — and four members are
duplicated with byte-for-byte identical lowering. This is both a user-facing
ambiguity ("which one do I call?") and a maintenance hazard (the two copies will
drift the moment one is touched). A quick sweep turned up one secondary doc-level
overlap (
TextvsUnicodecase mapping) and a set of benign same-verb/different-subjectcollisions that need no action. Details below.
Primary finding —
System.*⊃Os.*duplicationBoth namespaces are shipped and documented (
docs/language/system/,docs/language/os/). These members exist in both, with the same semantics:System.*loweringOs.*loweringarg_count()arg_count→load i32, ptr @L_argc(emit_intrin.ludic:60)load i32, ptr @L_argc(emit_os.ludic:47)arg(i)arg→ load@L_argv(emit_intrin.ludic:61)@L_argv(emit_os.ludic:48)env(name)getenv→@getenv(emit_intrin.ludic:80)@getenv(emit_os.ludic:61)exit(code)exit→@exit+unreachable(emit_intrin.ludic:67)@exit+unreachable(emit_os.ludic:54)The dispatch for
System.*lives at emit_expr.ludic:346(aliases each method to a bare intrinsic), and
Os.*atemit_expr.ludic:250 →
emit_os_ns.Beyond the exact duplicates, the two namespaces overlap on the same domain with
slightly different shapes:
System.stdout/System.stderrreturn a rawFILE*handle;
Os.stdout_write(s)/Os.stderr_write(s)write a string directly.Same concern, two spellings.
Os.*additionally owns the richer, curated surface:args(),env_or,has_env,set_env,unset_env,platform,arch, and the known-folderhelpers (
save_dir/config_dir/cache_dir/temp_dir).System.*additionally owns the low-level file/process bits:file_open/read/ write/seek/tell/close,read_char,run.So
System.*is really an older low-level grab-bag;Os.*(added in #21) is thenewer curated environment interface. The env/args/exit/streams slice of
System.*is now redundant with
Os.*, and the file slice is exactly what the open Fs/Pathproposal (#10) intends to wrap ("Some low-level pieces already exist as bare builtins
(
file_*,read_char) … wrap them into one safe, ergonomic, namespaced API").Why it matters
System.envandOs.envhave identical docs/signatures. A newcomerhas no way to know they're the same call.
Os.exit's codegen andSystem.exitsilently keeps the old behavior (and vice-versa).Proposed direction (for discussion)
Make
Os.*the canonical environment/process namespace and retire the overlappingSystem.*members:file_*,read_char,run) into the Fs/Pathdesign (#10) rather than leaving them under
System.*.System.{arg,arg_count,env,exit}andSystem.{stdout,stderr}onto theOs.*equivalents — either delete them, or makeSystem.*a thin deprecated aliasthat calls the same
emit_os_nspath so the lowering exists in exactly one place.docs/language/system/*pages for anything that moves.At minimum, even if
System.*is kept for now, the four duplicated methods shouldshare one codegen path instead of two copy-pasted ones.
Secondary finding —
Text.upper/lowervsUnicode.upper/lowerText.upperis ASCII-only (fn_str_upper, emit_text.ludic:53)while
Unicode.upperdoes full Unicode case mapping (fn_uni_case,emit_unicode.ludic:60) — genuinely different behavior,
but their docs are indistinguishable (
sig: … -> string, tip "Uppercase a string").Not code duplication, but a real trap: pick the wrong one and non-ASCII text is
silently mishandled. The docs should state the ASCII-only limit on
Text.upper/lowerand cross-link to
Unicode.*. (TextvsUnicodeforchar_at/len/lengthisfine — the tips already say "byte" vs "code point".)
Benign collisions (no action — listed for completeness)
Method names shared across namespaces that are correctly "same verb, different subject
/ receiver type":
Math/Vector/Color.lerp,Date/DateTime.{year,month,day,weekday},Map/World.size,Math/Random.sign,DateTime/Uuid.parse,Date/Uuid.new,List/Text.{contains,index_of},List/Screen.clear,Clock/Time.now(simulated
DateTimevs wall-clock epochint— distinct domains), etc. These arefine as-is.
Investigation covered every documented namespace method (
docs/language/*/*.md,279 members) plus the
emit_*_nsdispatch inselfhost/.Done in
ac1e8d1.Direction taken: made
Os.*the canonical environment/process namespace and retired the overlappingSystem.*members rather than aliasing them — the strongest of the proposed options, since it removes the ambiguity outright instead of leaving two spellings.Retired (all now route to
Os.*):System.arg→Os.arg,System.arg_count→Os.arg_count,System.env→Os.env,System.exit→Os.exit, and the stream pairSystem.stdout/System.stderr→Os.stdout_write/Os.stderr_write. Calling a retired member is now a hard compile error (unknown builtin System.env), not silent duplication.Kept under
System.*: the genuinely-unique low-level surface — the rawFILE*handle API (file_open/read/write/seek/tell/close),read_char, andrun. These are exactly the "grab-bag" the Fs/Path work (#10, now shipped asFs.*/Path.*) wraps at a higher level; the raw handles stay as the escape hatch.On the "one codegen path" ask: the four duplicated lowerings are no longer copy-pasted across two user-facing namespaces. The bare
arg/exit/getenv/file_stdout/file_stderrintrinsics remain — but as the primitive layer the self-hosted compiler itself compiles against (main.ludicet al. call them directly), not as a second public spelling.Secondary finding (Text vs Unicode):
Text.upper/Text.lowerdocs now state the ASCII-only limit explicitly and cross-link toUnicode.upper/Unicode.lowerfor full Unicode case mapping.Removed the six now-dead
docs/language/system/*pages, retuned the section blurb, and updatedinventory.json+ the LSP signature table. Reseeded; the C-free bootstrap fixpoint holds. All suites green (56 test / 29 selfhost / 29 test-tools) and docs still cover every implemented feature (291 namespace methods).The benign same-verb/different-subject collisions listed in the issue were left as-is, as recommended.