From: "rubyFeedback (robert heiler) via ruby-core" Date: 2023-10-30T13:56:31+00:00 Subject: [ruby-core:115204] [Ruby master Feature#19979] Allow methods to declare that they don't accept a block via `&nil` Issue #19979 has been updated by rubyFeedback (robert heiler). > Is this a frequent error? > I think the only times I saw it is due to confusion of the priority > of do/end vs {/} (which needs to be learned separately anyway), and > for some poorly-designed open methods which don't take a block. Personally I never saw such an error and can not recall having made such an error either. I also never had a need to prevent passing of blocks, but I also agree that there may be situations where one may specifically want to disable that, even though I personally never had such a use case. I think the only times when I had issues with calling parent methods, and it confused me, was when I used super() versus super without the (). Since then I, oddly enough, transitioned towards using super() as default (unless I need the behaviour of super without () specifically). If we reason that ruby is to be a flexible language, then I think we can reason that ruby should have a way to disallow passing a block, just as you, as a ruby developer, can decide on how many arguments a method should accept, including keyword arguments (which, by the way, also confused me when I first saw them; I also dislike when a third party API demands of me to use keyword arguments - I always felt that an option hash is less restrictive and in some ways equivalent.) Note that personally I am not a huge fan of the &nil, but I also don't want to be too discouraging. One concern I have is that it may still confuse users, when they see &block and then &nil and then &urmom ... not sure I am a huge fan of that. I kind of default to &block - somehow to me this is the most sensible name for a block variable to be had. If others use &nil, in their code base - well, they can do what they want to in their code base. I only focus on trying to maintain my own ruby code and hope that there is some sanity in what I maintain. :) But, the TL;DR, I agree that it does not seem to be too common, at the least I can not recall having seen it before. I don't know all the ruby code out there, though. > I think even if it was accepted it would be very unlikely > for gems to use &nil, first they would need to require > Ruby 3.3+ and second it's extra noise in the source code > with almost no benefit for the gem. > So I think in practice this would not achieve much. I kind of agree with that, but I suppose this may be a long term suggestion and change, so you could re-evaluate in, say +3 years. It may not be too overly common though; I can not think of any real use case I have where I specifically need to prevent passing of a block. To me I always treated block variables as a nice, additional argument to allow for more flexibility, rather than as a basic-must-have that is the main driving factor for designing APIs, libraries and use cases. I do not think that "only on ruby 3.3" is a necessary exclusive criterium, though. For instance, I try to keep my code always up-to-date with the latest ruby xmas release. Sometimes I may try to maintain backwards compatibility, but it is never my primary focus. I always default with MRI these days; it simply is easier to do so. (I understand that some implementations lag behind, e. g. jruby - I think they are still not at 3.2 or so if I recall headius' summary-issue-tracker for it.) > For methods which sound like they might take a block but > don't, the raise ArgumentError, ... above seems a good > existing solution. Understandable as well, but I would like to point out that raising an error may not necessarily always be that useful or necessary. For instance, I tend to not care too much about block variables, so I rarely ever raise an error about it. At best I may give a notice to the user, but that's about it for block variables usually. > It's also a bit similar to **nil, which is almost never used. Agreed. I actually also never used **nil so far. zverok wrote: > So I am also not sure where the currently proposed feature would help. Agreed, but matz also discussed this before, so there may be a use case, even if it may be very small. zverok wrote: > Also, as a negative consequence, I can imagine a linter-enforced > rule to "always add this declaration when the method doesn't > need/accept block," which will make a lot of code worse. I think that can be tweaked, e. g. like rubocop styling rules. Any linter that would tell me to sprinkle my sane code via &nil I'd throw out the door though. ;) zverok wrote: > OTOH, would help a lot (and I am not sure why is it closed, no reasons are > given at https://bugs.ruby-lang.org/issues/15554?tab=history#note-9 That's from 5 years ago or so. Perhaps it may be useful to have it at an upcoming developer meeting, discussed, and then also someone who feels motivated and has time, to explain the decision making towards pro or con of it anyway, since that seems to be missing slightly (or, at the least, the context has not been put down in detail; ufuk here may have given the biggest summary so far about it; also note that ko1 in #15554 also mentioned a warning rather than the raise ArgumentError as pointed out by eregon. I guess it comes down to how you want to treat block variables in general, which is a design consideration of ruby.) ---------------------------------------- Feature #19979: Allow methods to declare that they don't accept a block via `&nil` https://bugs.ruby-lang.org/issues/19979#change-105116 * Author: ufuk (Ufuk Kayserilioglu) * Status: Open * Priority: Normal ---------------------------------------- ## Abstract This feature proposes new syntax to allow methods to explicitly declare that they don't accept blocks, and makes passing of a block to such methods an error. ## Background In #15554, it was proposed to automatically detect methods that do not use the block passed to them, and to error if a block was passed to such methods. As far as I can tell, it was later on closed since #10499 solved a large part of the problem. That proposal has, as part of [a dev meeting discussion](https://github.com/ruby/dev-meeting-log/blob/b4357853c03dfe71b6eab320d5642d463854f50f/2019/DevMeeting-2019-01-10.md?plain=1#L110-L120), a proposal from @matz to allow methods to use `&nil` to explicitly declare that they don't accept a block. At the time, the proposal was trying to solve a bigger problem, so this sub-proposal was never considered seriously. However, notes in the proposal say: > It is explicit, but it is tough to add this `&nil` parameter declaration to all of methods (do you want to add it to `def []=(i, e, &nil)`?). (I agree `&nil` is valuable on some situations) This proposal extracts that sub-proposal to make this a new language feature. ## Proposal In Ruby, it is always valid for the caller to pass a block to a method call, even if the callee is not expecting a block to be passed. This leads to subtle user errors, where the author of some code assumes a method call uses a block, but the block passed to the method call is silently ignored. The proposal is to introduce `&nil` at method declaration sites to mean "This method does not accept a block". This is symmetric to the ability to pass `&nil` at call sites to mean "I am not passing a block to this method call", which is sometimes useful when making `super` calls (since blocks are always implicitly passed). Explicitly, the proposal is to make the following behaviour be a part of Ruby: ```ruby def find(item = nil, &nil) # some implementation that doesn't call `yield` or `block_given?` end find { |i| i == 42 } # => ArgumentError: passing block to the method `find' that does not accept a block. ``` ## Implementation I assume the implementation would be a grammar change to make `&nil` valid at method declaration sites, as well as raising an `ArgumentError` for methods that are called with a block but are declared with `&nil`. ## Evaluation Since I don't have an implementation, I can't make a proper evaluation of the feature proposal. However, I would expect the language changes to be minimal with no runtime costs for methods that don't use the `&nil` syntax. ## Discussion This proposal has much smaller scope than #15554 so that the Ruby language can start giving library authors the ability to explicitly mark their methods as not accepting a block. This is fully backward compatible, since it is an opt-in behaviour and not an opt-out one. Future directions after this feature proposal could be a way to signal to the VM that any method in a file that doesn't explicitly use `yield`/`block_given?` or explicitly declared a block parameter should be treated as not accepting a block. This can be done via some kind of pragma similar to `frozen_string_literal`, or through other means. However, such future directions are beyond the scope of this proposal. ## Summary Adding the ability for methods to declare that they don't accept a block will make writing code against such methods safer and more resilient, and will prevent silently ignored behaviour that is often hard to catch or troubleshoot. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/