-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] get
for container types returning an Option[T]
#35
Comments
But I don't like Option[T], it's messy to work with. |
1. Add existential operator:
2. Add existential call operator:
3. Special
|
get
for container types returning an Option[T]get
for container types returning an Option[T]
Why add |
Please, do not treat options specially in the language (special if handling) - Nim is powerful enough to provide a nice syntax for options without special support. For instance, libraries (such as patty) could provide pattern matching for options |
An existential operator should extend to |
In math,
|
@Araq can't you have just The problem is that currently there is no one good way to signify a value is actually optional: everything has its own way to somehow represent "value is missing" and even with |
It's not about syntax, you can make it as short as you want and I still wouldn't like |
@Araq, it's always the responsibility of the API designer (or the data structures designer) to use the right tool for the job. If some API would be better off with a But in the particular case being discussed here, the container types ought to support a way to search for a key that doesn't exist. The objective reality is that by using
|
When it comes to error handling my best experiences stem from my Scala days where error handling is done via things like To address the performance aspect first: As long as there is a @Araq The fact that you are arguing against The following shows the most basic example for nested error handling, i.e., a database may or may not have a user, and a user may or may not have an address. case class DB(handle: Int)
case class User(name: String)
case class Address(street: String)
def fetchUser(db: DB): Option[User] = Some(User("John"))
def fetchAddress(user: User): Option[Address] = Some(Address("SomeStreet")) Now any nested lookup is fully composable via def lookupStreet(db: Option[DB]) =
db.flatMap(db => fetchUser(db))
.flatMap(user => fetchAddress(user))
.map(_.street)
// or if you perfer the 'for comprehension' syntax:
// (note that this is simply syntactic sugar for the above)
def lookupStreetFor(db: Option[DB]) =
for (
db <- db;
user <- fetchUser(db);
address <- fetchAddress(user)
) yield
address.street The obvious benefits:
There are also less obvious benefits of such a monadic approach because it can be extended nicely. For instance it would be possible to
Sorry for the long post, but I just don't feel it is appropriate to discard |
I told you you can make the syntax as short as you like and I still wouldn't buy it.
That is not true. Ok, instead of an
That is only true if you mapped every invalid value into the
I don't argue about performance, Option[T] a) is yet another way to do things. Not too mention that |
But you are arguing by complaining that it's messy to work with and giving a syntax example which is an anti-pattern.
I was referring to the
Never had this issue in many years working with them. If you need a custom validation function just inject it into the chained functions (example below).
Why "yet another"? There is just exceptions and the standard library already provides
What kind of proof is this? I just gave an example that demonstrates the composability of nested lookups. We are talking about "optional return values" from container lookups/searches here. I don't see what the non-existence of
I think we are mixing up optional input with optional output here. For instance if you lookup an for (
i <- map.get(key); // returns Some(Int)
iValidated <- validate(i, A, B); // returns Some(Int) if i in A .. B
result <- compute(iValidated)
) yield
result Benefit: |
This should be obvious, but the existential operator I proposed above is equivalent to the @Araq, you still haven't addressed my comment that the API of the container types just doesn't have the same functionality without the proposed |
Obviously a hand wavy one. ;-) But this was not the first time I mentioned these example. Consider a version of Scala where out-of-memory is dealt via Option[T]. By your argument it would work out just fine. I'm not buying that. |
That can also be done with a template/macro that takes an |
The problem with these as far as I can see is that they do not compose well. |
Can we agree to add the low-level efficient interface with the |
Fine with me. |
What would that look like? |
Turns out that the required work-around already exists as a template called import
options, tables
var tbl = initTable[string, int]()
tbl["foo"] = 10
tbl["bar"] = 20
proc getOpt[A,B](tbl: var Table[A, B], key: A): Option[B] =
tbl.withValue(key, value) do:
return some(value[])
do:
return none(B)
var
o1 = tbl.getOpt("foo")
o2 = tbl.getOpt("baz")
echo o1
echo o2 Currently, the injected |
Also, it would be nice if the template can work both as a statement and as an expression. This can be achieved by setting the result type to var x = tbl.withValue("foo", value, some(value), none(int))
var y = tbl.withValue("foo", value) do:
some(value)
do:
none(int) |
Third flaw is that |
I've added a kind of existential operator and a |
Here's an example of what this syntax can look like with nim today:
this does early return in case of error in |
This RFC is stale because it has been open for 1095 days with no activity. Contribute a fix or comment on the issue, or it will be closed in 7 days. |
If I'm using the
options
module in my program it sucks that not all modules use it. It would be nice to implement it for the containers in the stdlib, for exampleproc get*[K, V](t: Table[K, V], key: K): Option[V]
.We should standardise on the name too, it should be consistent across the stdlib.
The text was updated successfully, but these errors were encountered: