Closed nemo83 closed 1 year ago
Interesting proposal!
Implementing some setters might work for this. The setter then returns the updated value.
Eg.:
valueSentToVault: Value = totalValueLocked.set_lovelace(2000000)
Remember that all values are immutable, so the only thing a setter can do IS return something new.
What do you think?
Not sure if setters should be auto-generated for user types (eg. set_<name-of-field>
)
Interesting proposal!
Implementing some setters might work for this. The setter then returns the updated value.
Eg.:
valueSentToVault: Value = totalValueLocked.set_lovelace(2000000)
Remember that all values are immutable, so the only thing a setter can do IS return something new.
What do you think?
thanks, I'm only reporting the scala features that I find drastically reduce typing. So I might come up w/ a few more of these as I write more and more helios code.
For the record, I'm totally addicted to the tool.
I don't think I set_
as it recalls mutability, if copy(lovelace = 2000000)
isnot possible, I would maybe opt for with_lovelace(2000000)
in a builder style approach (that still I don't fully like, but at least is not teh set_
.
Is the copy(lovelace= 2000000)
hard/impossible to autogenerate? As that would definitely be my favourite options.
We can add copy
as special syntax (similar to how switch
is special syntax)
But we'd have to be very sure that that's the best syntax possible
Anything that you can think of that can be improved upon wrt. scala?
Anything that you can think of that can be improved upon wrt. scala?
Not sure what you mean here, but the copy
method is the only scala syntax feature I can think of that could be beneficial to helios. The other thing I use all the time is pattern matching (switch), that helios has already.
Wrt to alternative to the copy
I would avoid the set
any other thing sounds good to me.
Variations on the syntax are possible:
my_struct.copy(field1 = <expr1>, field2 = <expr1>)
or
my_struct.copy{field1 = <expr1>, field2 = <expr1>}
or
my_struct.copy{field1 => <expr1>, field2 => <expr1>}
or
my_struct.copy{field1: <expr1>, field2: <expr1>}
I think the last one is most consistent with the rest of Helios. @nemo83 What do you think?
I think the last one is most consistent with the rest of Helios. @nemo83 What do you think?
I am used to the first example. But I'd be interested in seeing examples of where 4 is already used in helios.
Thanks 🙏
EDIT:
Some addition. I'm not sure the .copy
method should be seen as a special syntax. In Functional Programming objects (values) are immutable.
Helios struct
s seem to be what in scala are called case classes
and have a .copy
method by default. Because of being methods, they have no special syntax. From a user (helios programmer) PoV, forcing a different syntax from a simple method invocation, could communicated that .copy
is somehow special, while it's just a method. Also, they would need to rememeber that .copy
requires a special syntax.
A simple scala example
case class Person(name: String, age: Int)
val giovanni = Person("Giovanni", 39)
// some time in April
val giovanniIs40 = giovanni.copy(age = 40) // the giovanni object above is still 39 (lucky it!)
I would stick with the syntax I proposed at the beginning of the thread:
newValue: Value = myValue.copy(lovelaces = 2000000)
An option I could consider is to use :
instead of =
if there is already a convention to assign value to params referenced by name with :
.
An issue I see with using scala copy
syntax is needing to expand key-based arguments to the rest of the language, otherwise, it feels incomplete.
My reasoning for the braces syntax is that it is like a literal struct, except it does not need all the fields.
Maybe expanding key-based arguments to the rest of the language is not such a bad idea, and also add the capability for optional arguments.
Perhaps we could use the C# syntax ?:
myValue.copy(lovelace: 200000)
Other things to figure out:
func my_func(a: Int, b: Int = 0) -> Int {
...
}
func my_func(a: Int, b: Int = a*2) -> Int {
fn = (c: Int, d: Int = b) -> {...}; ...
}
func my_func(a: Int, b = 0) -> Int {
...
}
Actually, now that I think of it: we have to use the colon syntax because the equals syntax is already a part of a valid expression (and function call arguments can be arbitrary expressions)
What should the type signature look like for functions with optional arguments?
Eg.
(a: Int, b? Int) -> Int
Which could be cast into (a: Int) -> Int
or (a: Int, b: Int) -> Int
automatically, or even (Int) -> Int
or (Int, Int) -> Int
(arg names are now part of the type)
(I don't think I've ever seen a language do that right)
What should the type signature look like for functions with optional arguments?
Eg.
(a: Int, b? Int) -> Int
Which could be cast into
(a: Int) -> Int
or(a: Int, b: Int) -> Int
automatically, or even(Int) -> Int
or(Int, Int) -> Int
(arg names are now part of the type)(I don't think I've ever seen a language do that right)
This is a very delicate topic, and in this case I can see now why in a way copy
is different.
For me optionality should still be wrapped into the Option[]
type.
So the :?
syntax would/should be only for copy
method as it won't make sense elsewhere.
To be clear: copy
might have to be a special builtin function that wouldn't be usable as a value (it would have to be called immediately).
Another version of syntax for functions with optional args could be: (a: Int; b: Int, c: Int) -> Int
(so anything after ;
is optional)
The semi-colon approach might not be so clean for a function with only optional arguments:
func add(;a: Int, b: Int) -> Int {
...
}
An alternative could be:
func add(a: Int, b ? Int = 0) -> Int {
...
}
// type-signature of "add":
// (Int, ? Int) -> Int
// (a: Int, b ? Int) -> Int
Or simply reuse =
symbol if the conventional syntax is preferred:
func add(a: Int, b: Int = 0) -> Int {
...
}
// type-signature of "add":
// (Int, Int =) -> Int
// (a: Int, b: Int =) -> Int
Another variation in which the type signature differs from the definition:
func add(a: Int, b: Int = 0) -> Int {
...
}
// type signature of "add":
// (a: Int, b: ?Int) -> Int
// (Int, ?Int) -> Int
copy
could actually be an auto-generated function that can be passed around as a value before calling:
myStruct.copy: (name1: ?Type1, name2: ?Type2, ...) -> MyStruct
I've implemented default values and copy
in v0.13.0 of Helios. @nemo83 When you have some time, could you test that it works for your cases?
https://www.hyperion-bt.org/helios-book/lang/functions/optional_arguments.html https://www.hyperion-bt.org/helios-book/lang/automatic-methods.html#copy
Huge milestone for Helios.
Less code Less bugs
Given the functional nature of helios, it would be amazing a if
copy
function could be implemented for onchain types. This would make helios less error prone by reducing verbosity.Example.
We have a combination of lovelace/tokens at a utxo. We know that the value it's legit but we don't care what's in it, neither we want to keep track, and we want to split into two parts: