Thanks for the feedback. I'm replying below to all three of you, as
it's all related. I'm hearing strong support for making asynchronous
calls explicit, which is fine with me.
“v as T” syntax is simpler than "as<T>(v)”.
I see one disadvantage with the "as" syntax: the whitespace will lead
to additional parentheses being required in some contexts. For
example, with T being a record: "(v as T)$foobar" vs
"as<T>(v)$foobar". Not necessarily a showstopper though. The "as"
syntax does feel more in line with other Bro syntax.
Are there other ideas to express casts?
Is there a reason "type(v)” can’t be stored? I’d probably find it
more intuitive if it could, else I can see myself forgetting or making
mistakes related to that.
Mind elaborating how you would expect to use that? My reasoning for
foregoing storage was that I couldn't really see much use for having a
type stored in variable in the first place because there aren't really
any operations that you could then use on that variable (other than
generic ones, like printing it).
Alternative to even providing “type(v)”, you could have a “v is T”
I like that. That avoids the question of storing types altogether.
operation and to use an explicit/new “typeswitch (v)” statement
instead of re-using “switch (type(v))”.
Hmm ... I'd prefer not introduce a new switch statement. However,
seems the existing switch could just infer that it's maching types by
looking at case values: if they are types, it'd use "is" for
comparision.
case bool -> b:
case count:
Good point, I like that.
It might even be useful to try and spec out the co-routine support now
and see how this specific use-case fits in with that.
Need to think about that, would clearly be nice if we could pave the
way for that already.
- In the switch statement, I would require that a user either provide
a default case or fully enumerates all cases. Otherwise it's too
easy to cause harder-to-debug run-time errors.
Full enumeration doesn't seem possible, that would mean all possible
types, no?
Are we requiring "default" for the standard switch statement? If so, I
agree it makes sense to do the same here (otherwise, not so sure,
because of consistency).
case b: bool
case s: set[int]
case r: some_record
Interesting thought. I had this at first:
case b: bool: ...
case s: set[int]: ...
case r: some_record: ...
That mimics the existing syntax more closely, but ends up being ugly
with the two colons. I kind of like your idea, even though it makes
the syntax a bit non-standard. However, I'm not sure the parser could
deal with that easily (because there's no clear separation between the
type and the following code). Also, this might not fit so well with
Jon's idea of making the identifier optional.
- Why do we need a string comparison here?
if ( type(v) == string )
I believe you misread this: "string" *is* a type.
- Uplevelling, why do we need type() in the first place? Can't we just
overload the switch statement to work on types as well? Or do you
have other use cases in mind?
My main other use case was offering if-style comparision as well for
types (see previous point). But if we do "is" for that, we indeed
wouldn't need the type() anymore.
However, if we make timeouts mandatory, I woudn't mind dropping the
async keyword.
I'm going back and forth on whether to make timeouts mandatory. I
think we need to have a default timeout in any case, we cannot have
calls linger around forever. But explicitly specifying one each time
takes away some of the simplicity. On the other hand, with a default
timeout we'd probably need to throw runtime errors instead of
returning something, and Bro isn't good with tons of runtime errors
(which could happen here).