Differences from Ruby
KupCAD borrows Ruby’s syntax but keeps a simpler model. These differences are design choices, not missing pieces.
Calls and callables
Section titled “Calls and callables”- Lambdas are the only callable values, and they are called with
.call:f.call(3). There is noproc,Proc.neworlambda { }, and nof.()orf[3];f(3)is aTypeError. See Lambdas. - A lambda behaves exactly like a block.
returnandnextleave only the block or lambda, never the method around it;breakis how a block stops an iteration with a result. Both are lenient about arguments: missing ones areniland extras are dropped. See break, next and return. - Block parameters don’t unpack an Array by themselves: write
|(a, b)|. Map iterators still pass the key and value separately. See Arguments. - No
&:nameshorthand: write{ |v| v.name }. - No Enumerator:
each_with_index,each_consandeach_slicewithout a block give an Array. See Array. - An object’s own methods are called through
self.inside a class: a bare name is a variable. See Calling. - Visibility is declared per method, with
private def(orpublic def). There are noprivatelines that change the methods after them, and noprotected. See Visibility.
Variables
Section titled “Variables”- Methods read top-level variables, which Ruby’s can’t; assigning inside a method still makes a local. See Scopes.
$nameis a variable of its file that methods can assign, not a process-wide global, and there are no special variables like$0. See Dollar variables.- A variable exists once its assignment has run. One assigned only in a branch that didn’t
run is a
NameErrorwhen read, where Ruby givesnil.
Values and operators
Section titled “Values and operators”- Every number is a float:
10 / 4is2.5, and there are no separate Integer and Float classes. See Numbers. and,orandnotare&&,||and!, at the same precedence:x = true and falseassignsfalse. See Precedence.<,<=,>and>=compare Numbers only;<=>also orders Strings.- No
String * n,Array * norArray - Array: they areTypeErrors. a&.m.ncallsnonnilwhenaisnil:&.skips only its own call. See Safe call.defined?givestrueornil, not a description.- A quoted key before
:is a String:{ "a": 1 }and{ "a b": 1 }key by the Strings"a"and"a b", where Ruby makes Symbols. Write{ :"a b" => 1 }for a Symbol. See Maps. - Heredocs aren’t interpolated, and
%Wand%Iread as%wand%i. See Heredocs. - No endless or beginless ranges (
1..).
Control flow
Section titled “Control flow”- A loop header ends at the line break:
for x in xs doandwhile c doare the compile errormisplaced-do. begin ... end while condchecks the condition first, like anywhilemodifier.- No
loop do ... end: writewhile true.
See Control flow.
Classes and errors
Section titled “Classes and errors”- Built-in classes are sealed:
Solid,Number,Array,Mathand the rest can’t be reopened, and the classes can’t be subclassed. Only the error classes can be subclassed. See Built-in classes are sealed. - Operator methods can’t be defined (
def ==(other)), and instances are equal only to themselves. - No
extendormodule_function;includetakes a module in a class body. - An index out of bounds is an
IndexError([1, 2][5]), where Ruby givesnil. NoMethodErroris not a kind ofNameError. See Error classes.rescuehas noelseclause, and a bareraisedoesn’t raise again: writeraise e.- Recursion has fixed limits: 100,000 calls deep, 200 nested inside built-ins. Past either,
Call stack overflowstops the run and can’t be rescued. See Recursion. - No
retry,aliasor__method__. A script is deterministic, so aretrywith nothing changed would fail again forever: write the fallback in therescueclause. For a second name, define it:def d = self.diameter. All three read as undefined variables, so they fail when the line runs, not when the script is checked.