Somehow add metaprogramming to type parameters #1639
Replies: 8 comments 7 replies
-
Whether
Inconsistently, it’s |
Beta Was this translation helpful? Give feedback.
-
Relevant: #1223 (comment) |
Beta Was this translation helpful? Give feedback.
-
One problem with the |
Beta Was this translation helpful? Give feedback.
-
This isn’t intuitive. Ability to selectively forward def only_forward_return: (*nil, **nil, &nil, ...base) |
Beta Was this translation helpful? Give feedback.
-
This is my idea, originally dumped in the Discord. Samp would like me to compile the thoughts over here. [seat reservation] |
Beta Was this translation helpful? Give feedback.
-
There are several niche cases that having type splatting solves:
It’s actually almost possible to use the same char to splat, since
This is like @sampersand’s original idea –
We could restrict the fragments to literal typs only, since
Splatting We shouldn’t touch the existing syntaxes, however, and thus unfortunately All existing proposals are more or less ugly, if not limited. They almost look like macros to some extent, yet they aren’t the kind of macros that solve WET issues.
If we are gonna add something that looks like macros and quacks like macros, we might as well go all in and actually add macros. |
Beta Was this translation helpful? Give feedback.
-
New, better idea!module Kernel
type open_args = (
path file,
?(int | string)? vmode,
?int vperm,
?mode: (int | string)?,
?perm: int?,
?flags: int?,
?textmode: boolish,
?binmode: boolish,
?encoding: encoding?,
?extenc: encoding?,
?intenc: encoding?,
)
def self?.open: open_args -> File
| [T] open_args { (File) -> T } -> T
end Yes,
|
Beta Was this translation helpful? Give feedback.
-
module Kernel
type open_args = [path file, …]
type open_kwargs = {?mode: (int | string)?, …}
# Unchanged from Samp’s syntax,
# but note that both requires support for optional fields in explicity tuples and records
def self?.open: (*?open_args, **?open_kwargs) -> File
| [R] (*?open_args, **?open_kwargs) { (File) -> R } -> R
end class MyLogger
type level = :debug | :info | :warn | :error | :fatal
type log_args = [?String message, ?String call_site, ?cause: Exception?]
def log: (level, *?log_args, **untyped extra_info) ?{ () -> String } -> void
def debug: (*?log_args, **untyped extra_info) ?{ () -> String } -> void
… 抛砖引玉; inspired by Line 992 in 36f84b7 |
Beta Was this translation helpful? Give feedback.
-
Overview
Currently in RBS, methods and types take a fixed amount of known parameters. This makes sense for the majority of cases, but occasionally is insufficient (especially when dealing with code that forwards arguments/reuse of RBS interfaces, etc.). The syntax is bikesheddable.
Motivating Examples
1.
Kernel#open
and friendsThe
Kernel#open
function, along with things likeIO.new
,File.read
, etc. all have a (fairly lengthy) common set of keyword arguments they accept. For example,Kernel#open
(slightly abridged):Repeating them across all similar functions is both error-prone, and difficult to maintain. An alternative would be something like this:
2. Creating a
_Call
interfaceWe currently have special syntactic support for Procs (
^(...) -> ...
), but not things that define.call
. Most of the time in Ruby, you don't care about explicitly taking aProc
, but rather something that defines.call(...)
, which can also encompassMethod
s and custom types. It would be nice if we could have support for_Call
(and friends, like_Index
and_IndexAssign
). Here's an example (like before, syntax bikesheddable):You could then use the interface like
_Call[[Integer], { fizz: String, buzz: String }, nil, String]
. Like before, the syntax can be modified, but I think the idea of allowing people to "forward" arguments from interfaces has merit.3. Add full support for "forwarding methods"
Similar to point #1, this would make it easier for end users to create their own "forwarding methods" (eg
def debug(...) = log(:debug, ...)
:Syntax possibilities
As you've seen before, one of the possibilities we could use would be to make use of our tuple/record types, and simply have some special syntax to indicate that we want to "splat" them out into the arguments for the function.
[** < typename]
...
Another idea I've been kicking around is making use of
...
. Currently, in RBS you can already use...
(such asdef foo: ... | <more definitions here>
), which is used to mean "accept any signatures that parent classes define, in addition to any other definitions I'll add."I want to somehow use the
...
syntax as part of RBS as well, like Ruby does. (Like ruby,...
can only be used once per function signature, as the last argument). Here's just a few ideas of how it could be used:Method signatures
Upsides:
...
syntaxDownsides:
**nil
might conflict with ruby's**nil
def open: (<positional args here>, ...IO#open) -> File
needs to not parse#
as a comment)-> foo
syntax is now not always required for functions (which means we can't use omitting-> x
as an alias for-> void
, or other purposes)Generics forwarding
We can also use
...
to forward generic parameters:There's probably more examples of generics using this, i'll add them when I think of them.
Beta Was this translation helpful? Give feedback.
All reactions