Stream: ideas

Topic: Default values in ROC compared to JavaScript


view this post on Zulip Brian Teague (Feb 25 2024 at 05:13):

So I did some research on how JavaScript handles default values, and wanted to document that here. Do we even need ? in the type definition?

--Do default values need to apply to record type only?
optionalRecord : {a: Num a, b: Num a, c ? Num a}
optionalRecord = {a:1 b:2}

--JavaScript allows default values for function arguments with equal sign regardless of the type
primitveType = (n=1)-> n+1
tupleType = ([a,b=1])->a+b
ObjectType = ({a,b=2})->a+b

--Can default values be applied to all types in ROC?  Should ROC even default values?
primitiveType : Num a -> Num a
primitiveType = \n ? 1 -> n + 1

tupleType : (Num a, Num a) -> Num a
tupleType = \(a,b ? 1,c) -> a + b + c

recordType : {a: Num a, b: Num a} -> Num a
recordType = \{a, b ? 2,c} -> a + b + c

callPrimitiveType =
    primitiveType _ --I used an underscore place holder to indicate the absence of a value

callTupleType =
    tupleType (1,_,2) --What to put in the middle here to represent an explicit missing value?

callRecordType =
    recordType {a:1,c:2} --Easier since we can just not pass b.


--More complex scenario with renaming variables for multiple instances of the same type
--Renaming variables and defaulting those variables would have to be supported at the same time.

--Destructuring inside the function definition
MyTuple : (Num a, Num a)
tupleType : MyTuple, MyTuple -> Num a
tupleType = \(a1,b1?2),(a2,b2?4)->(a1+a2)-(b1+b2)

callTupleType =
   tupleType (1, _) (3, _)

MyRecord : {a: Num a, b: Num a}
recordType : MyRecord, MyRecord -> Num a
recordType = \{a:a1,b:b1?2},{a:a2,b:b2?4}->(a1+a2)-(b1+b2)

callRecordType =
   recordType {a:1} {a:3}

--Destructuring in the body of the function
MyTuple : (Num a, Num a)
tupleType : MyTuple, MyTuple -> Num a
tupleType = \tuple1,tuple2->
    (a1,b1?2) = tuple1
    (a2,b2?4) = tuple2
    (a1+a2)-(b1+b2)

callTupleType =
   tupleType (1, _) (3, _)

MyRecord : {a: Num a, b: Num a}
recordType : MyRecord, MyRecord -> Num a
recordType = \obj1, obj2->
    {a:a1,b:b1?2} = obj1
    {a:a2,b:b2?4} = obj2
    (a1+a2)-(b1+b2)

callRecordType =
   recordType {a:1} {a:3}

The difficulty is ROC would have to know that the properties or values eventually get a default value inside the body or function definition if they are not provided when calling the function. If you don't pass a required value to the function, and there is no default, then ROC would obviously need to throw a compiler error.

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:24):

yes, that's what the ? in the type solves :big_smile:

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:25):

(it conveys that the field can safely be omitted because a default has been provided, and if it turns out that's not true, then the compiler can tell you about the disagreement)

view this post on Zulip Brian Teague (Feb 25 2024 at 05:31):

Would it be beneficial to ROC to add? for any type including tuples, not just records only?

defaultNum : ? Num a -> Num a
defaultNum = \n ? 1 -> n + 1

callDefaultNum =
   defaultNum _

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:39):

I think it would be detrimental. :big_smile:

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:40):

my conclusion from looking into optional positional arguments and "nullable types" in other languages is that they would lead to worse APIs in Roc, and so we should explicitly choose not to support either

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:40):

in contrast, I do think optional labeled arguments are valuable

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:41):

and that was the original motivation for optional record fields

view this post on Zulip Richard Feldman (Feb 25 2024 at 05:42):

I think it's worth exploring alternative designs to the current optional record field system, but I don't think introducing nullable types or optional positional arguments are things Roc should have :big_smile:

view this post on Zulip Brendan Hansknecht (Feb 25 2024 at 06:22):

Richard Feldman said:

my conclusion from looking into optional positional arguments and "nullable types" in other languages is that they would lead to worse APIs in Roc, and so we should explicitly choose not to support either

Can you explain this more? Specifically optional positional arguments. Not sure why nullable types matter for this. I am just thinking about default values.

view this post on Zulip Richard Feldman (Feb 25 2024 at 06:30):

basically I looked at:

view this post on Zulip Richard Feldman (Feb 25 2024 at 06:31):

and it seemed like in both situations the "positional optional arguments get used" designs were worse

view this post on Zulip Richard Feldman (Feb 25 2024 at 06:32):

leading me to conclude that those other languages (without naming names) would have better APIs if the languages dropped support for that feature :sweat_smile:

view this post on Zulip Richard Feldman (Feb 25 2024 at 06:34):

it's an interesting exercise - like try it for some Roc APIs, see where it feels like it would make sense to use that feature if it existed, and then compare it to the alternative design where that feature doesn't exist (both times trying to aim for the nicest design possible, with the only variable changing being whether or not you're using optional positional arguments in some way)

view this post on Zulip Brendan Hansknecht (Feb 25 2024 at 06:44):

And this comment is specific to positional optional args? Not named optional args?

view this post on Zulip Richard Feldman (Feb 25 2024 at 11:39):

yeah

view this post on Zulip Kevin Gillette (Mar 02 2024 at 13:32):

I agree with that outcome regarding default value handling :wink: but methodology-wise, aren't there situations in which you need to change more than one variable?

Limiting it to a single variable change at a time limits the range of outcomes that can be explored, since language features (and omissions) work together. Changing just one variable from X=A -> X=B might be a worse world (as might any change to X alone), yet X=B Y=D might be an altogether better world than the current arrangement of X=A Y=C

I'm just zooming in on your use of the words "with the only variable changing"...


Last updated: Jun 16 2026 at 16:19 UTC