Feature #13683
closedAdd strict Enumerable#single
Added by dnagir (Dmytrii Nagirniak) over 8 years ago. Updated about 1 month ago.
Description
Summary¶
This is inspired by other languages and frameworks, such as LINQ's Single (pardon MSDN reference), which has very big distinction between first and single element of a
collection.
-
firstnormally returns the top element, and the developer assumes
there could be many; -
singlereturns one and only one element, and it is an error if there
are none or more than one.
We, in Ruby world, very often write fetch_by('something').first
assuming there's only one element that can be returned there.
But in majority of the cases, we really want a single element.
The problems with using first in this case:
- developer needs to explicitly double check the result isn't
nil - in case of corrupted data (more than one item returned), it will never
be noticed
Enumerable#single addresses those problems in a very strong and
specific way that may save the world by simply switching from first to
single.
Other information¶
- we may come with a better internal implementation (than
self.map) - better name could be used, maybe
onlyis better, or a bang version? - re-consider the "block" implementation in favour of a separate method (
single!,single_or { 'default' })
The original implementation is on the ActiveSupport https://github.com/rails/rails/pull/26206
But it was suggested to discuss the possibility of adding it to Ruby which would be amazing.
Updated by dnagir (Dmytrii Nagirniak) over 8 years ago
Actions
#1
- Tracker changed from Bug to Feature
Updated by Eregon (Benoit Daloze) over 8 years ago
Actions
#2
[ruby-core:81788]
+1, I have found this useful a few times as well.
Usually, I just define my own on Array, but it makes sense as well for Enumerable.
Updated by shevegen (Robert A. Heiler) over 8 years ago
Actions
#3
[ruby-core:81793]
I am not against or in favour of it but just a question.
What would the results be for the following code? In ruby (I find
it easier to read ruby code rather than the description actually):
[].single
[1].single
[1,2].single
[1,2,3].single
{}.single
{cat: 'Tom'}.single
{cat: 'Tom', mouse: 'Jerry'}.single
(And any other Enumerable objects I may have forgotten here.)
Updated by mame (Yusuke Endoh) over 8 years ago
Actions
#4
[ruby-core:81796]
+1. I always feel uncomfortable whenever using first for this purpose.
Updated by shan (Shannon Skipper) over 8 years ago
Actions
#5
[ruby-core:81798]
shevegen (Robert A. Heiler) wrote:
What would the results be for the following code? In ruby (I find
it easier to read ruby code rather than the description actually):[].single [1].single [1,2].single [1,2,3].single {}.single {cat: 'Tom'}.single {cat: 'Tom', mouse: 'Jerry'}.single (And any other Enumerable objects I may have forgotten here.)
I wrote a quick Ruby implementation before realizing there was a link to a Rails PR. Here are the results of your examples (and one added):
module Enumerable
def single
if one?
first
else
if block_given?
yield
else
raise "wrong collection size (actual #{size || count}, expected 1)"
end
end
end
end
[].single
#!> RuntimeError: wrong collection size (actual 0, expected 1)
[1].single
#=> 1
[1,2].single
#!> RuntimeError: wrong collection size (actual 2, expected 1)
[1,2,3].single
#!> RuntimeError: wrong collection size (actual 3, expected 1)
{}.single
#!> RuntimeError: wrong collection size (actual 0, expected 1)
{cat: 'Tom'}.single
#=> [:cat, "Tom"]
{cat: 'Tom', mouse: 'Jerry'}.single
#!> RuntimeError: wrong collection size (actual 2, expected 1)
[].single { 42 }
#=> 42
Edit: Caveat, my implementation doesn't handle an Infinite unsized enumerator, unlike the Rails PR which does.
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
Actions
#6
[ruby-core:81803]
- Description updated (diff)
Enumerable#first returns not only the first element, the elements at the beginning up to the number given by an optional argument.
How about an optional boolean argument exact to Enumerable#first or Enumerable#take?
Updated by dnagir (Dmytrii Nagirniak) over 8 years ago
Actions
#7
[ruby-core:81874]
shevegen (Robert A. Heiler) wrote:
What would the results be for the following code?
I would expect the following:
[].single # => error
[1].single # =>1
[1,2].single # => error
[1,2,3].single # => error
{}.single # => error
{cat: 'Tom'}.single # same as .first => [:cat, 'Tom']
{cat: 'Tom', mouse: 'Jerry'}.single # error
Updated by dnagir (Dmytrii Nagirniak) over 8 years ago
Actions
#8
[ruby-core:81875]
nobu (Nobuyoshi Nakada) wrote:
Enumerable#firstreturns not only the first element, the elements at the beginning up to the number given by an optional argument.How about an optional boolean argument
exacttoEnumerable#firstorEnumerable#take?
The purpose of the single suggested is to return one and only one element.
So it doesn't seem right to mix it up with first as it'll only add confusion, especially when used with a block.
On the other hand, I feel like a separate method that does one small thing well would be a much better API.
Updated by backus (John Backus) over 8 years ago
Actions
#9
[ruby-core:82140]
+1 to this proposal!! I have a Util.one(...) method in a half dozen or more projects. IMO #one is a nicer name than #single.
ROM exposes an interface I like when reading results from the db:
-
#one!- raise an error unless the result's#sizeis exactly1 -
#one- raise an error if the result's#sizeis greater than1. Return the result of#firstotherwise (so an empty result returnsnil).
I don't think the implementation should use the #one? predicate though. It would be confusing if [nil, true, false].single gave you nil instead of raising an error.
Updated by matz (Yukihiro Matsumoto) over 8 years ago
Actions
#10
[ruby-core:82983]
- Status changed from Open to Feedback
Hmm, I don't like the name single. Besides that, I think it may be useful for database access, but I don't see the use-case of this method for generic Enumerable.
Matz.
Updated by IotaSpencer (Ken Spencer) almost 8 years ago
Actions
#11
[ruby-core:86554]
matz (Yukihiro Matsumoto) wrote:
Hmm, I don't like the name
single. Besides that, I think it may be useful for database access, but I don't see the use-case of this method for generic Enumerable.Matz.
I think of single as a method towards mutual exclusivity.
If an Array or Enumerable from another expression should only have a single element,
then this gives the process a much faster setup and possible rescue, as I currently have
one of my projects checking for the existence of 3 headers, X-GitHub-Event, X-GitLab-Event,
and X-Gogs-Event, and I found the easiest way was to use one from Enumerable, but I wanted it
to error out so that I could catch it with the rest of my raised exceptions from other errors that
arise in the handling of the request.
How about these for suggestions.
one_or_raise
one_or_nothing
Part of my code for context.
events = {'github' => github, 'gitlab' => gitlab, 'gogs' => gogs
}
events_m_e = events.values.one?
case events_m_e
when true
event = 'push'
service = events.select { |key, value| value }.keys.first
when false
halt 400, {'Content-Type' => 'application/json'}, {message: 'events are mutually exclusive', status: 'failure'
}.to_json
else halt 400, {'Content-Type' => 'application/json'}, {'status': 'failure', 'message': 'something weird happened'
}
end
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
Actions
#12
[ruby-core:86665]
How about Enumerable#just(num=1) or Enumerable#only(num=1)?
Updated by shan (Shannon Skipper) over 7 years ago
Actions
#13
[ruby-core:88129]
nobu (Nobuyoshi Nakada) wrote:
How about
Enumerable#just(num=1)orEnumerable#only(num=1)?
Or maybe a slightly more verbose Enumerable#first_and_only(num = 1)?
Updated by lugray (Lisa Ugray) almost 7 years ago
Actions
#14
[ruby-core:92111]
I was pointed here after sharing the following code with my team mates. I really like the idea, and find I often reach for it. I second the name only.
module Enumerable
def only
only!
rescue IndexError
nil
end
def only!
raise(IndexError, "Count (#{count}) is not 1") if count != 1
first
end
end
Updated by jonathanhefner (Jonathan Hefner) over 6 years ago
Actions
#15
[ruby-core:95250]
matz (Yukihiro Matsumoto) wrote:
Hmm, I don't like the name
single. Besides that, I think it may be useful for database access, but I don't see the use-case of this method for generic Enumerable.
I use (monkey-patched) Enumerable#single in Ruby scripts which must fail fast when they encounter ambiguity. For example Nokogiri::HTML(html).css(selector).single to ensure an unambiguous matching HTML element. Or Dir.glob(pattern).single to ensure an unambiguous matching file.
Also, I agree that only would be a better name. And it would read more naturally if accepting an n argument like Enumerable#first does.
Updated by Dan0042 (Daniel DeLorme) over 6 years ago
Actions
#16
[ruby-core:95254]
+1
I actually have this as single in my own code, but only sounds fine also. I'd want a non-raising version (perhaps via a raise keyword arg?), as my usage tends to be like this:
if match = filenames.select{ |f| f.start_with?(prefix) }.single
redirect_to match
end
Updated by matz (Yukihiro Matsumoto) over 6 years ago
Actions
#17
[ruby-core:95382]
I don't like only either since these names do not describe the behavior.
Matz.
Updated by kinoppyd (Yasuhiro Kinoshita) over 6 years ago
Actions
#18
[ruby-core:95384]
[1, 2].mono
[1, 2].solo
[1, 2].alone
Updated by Hanmac (Hans Mackowiak) over 6 years ago
Actions
#19
[ruby-core:95388]
Dan0042 (Daniel DeLorme) wrote:
+1
I actually have this as
singlein my own code, butonlysounds fine also. I'd want a non-raising version (perhaps via araisekeyword arg?), as my usage tends to be like this:if match = filenames.select{ |f| f.start_with?(prefix) }.single redirect_to match end
instead of #select, shouldn't you use #find so it doesn't need to check the others when it already found a match?
Updated by Dan0042 (Daniel DeLorme) over 6 years ago
Actions
#20
[ruby-core:95399]
instead of
#select, shouldn't you use#findso it doesn't need to check the others when it already found a match?
No, because it should return nil when there's more than one match.
Updated by kaikuchn (Kai Kuchenbecker) over 6 years ago
Actions
#21
[ruby-core:95845]
I like one a lot. Especially since there's already one?.
Updated by fatkodima (Dima Fatko) over 5 years ago
Actions
#22
[ruby-core:99757]
I have opened a PR - https://github.com/ruby/ruby/pull/3470
# Returns one and only one item. Raises an error if there are none or more than one.
[99].one #=> 99
[].one #=> RuntimeError: collection is empty
[99, 100].one #=> RuntimeError: collection contains more than one item
# If collection is empty and no block was given, returns default value:
[].one(99) #=> 99
# If collection is empty and a block was given, returns the block's return value:
[].one { 99 } #=> 99
Updated by marcandre (Marc-Andre Lafortune) over 5 years ago
Actions
#23
[ruby-core:99758]
If we introduce one, it would be nice to support regexp; maybe use === for matching when given an argument?
%w[hello world].one(/ll/) # => 'hello'
Updated by sawa (Tsuyoshi Sawada) over 5 years ago
Actions
#24
[ruby-core:99765]
Having Enumerable#find take an optional keyword argument, say exception:, would make more sense, be useful, and have more generality.
[1].find(exception: true){true} # => 1
[1, 2, 3].find(exception: true){true} # >> Error
[].find(exception: true){true} # >> Error
%w[hello world].find(exception: true){/ll/ === _1} # => "hello"
%w[hello world].find(exception: true){/l/ === _1} # => Error
%w[hello world].find(exception: true){/x/ === _1} # => Error
Updated by Dan0042 (Daniel DeLorme) over 5 years ago
Actions
#25
[ruby-core:99768]
If collection is empty and a block was given, returns the block's return value:
I really think the block form should be like find/select
[1,2,3].one{ _1.even? } #=> 2
[1,2,3,4].one{ _1.even? } #=> error
[1,2,3,4].one(nil){ _1.even? } #=> nil
Having
Enumerable#findtake an optional keyword argument, sayexception:, would make more sense, be useful, and have more generality.
I don't think so; find only returns the first element found. An argument that makes it continue searching and return an exception if it finds a second match... that alters the fundamental behavior too much imho.
Updated by sawa (Tsuyoshi Sawada) over 5 years ago
Actions
#26
[ruby-core:99770]
Dan0042 (Daniel DeLorme) wrote in #note-25:
I really think the block form should be like find/select
[1,2,3].one{ _1.even? } #=> 2 [1,2,3,4].one{ _1.even? } #=> error [1,2,3,4].one(nil){ _1.even? } #=> nil
...
continue searching [...] that alters the fundamental behavior too much imho.
I think you are right.
But the word "one", which has the same etymology as the indefinite article "an", is not appropriate here. Its meaning is to arbitrarily pick out a single entity. This does match the concept discussed here.
I think the English word that best matches the concept is the definite article. This word presupposes that there is exactly one corresponding entity in the context, and picks that entity. If the presupposition is not satisfied, then the entire expression would be uninterpretable in the case of natural languages, which amounts to raising an exception in the case of programming languages.
[1, 2, 3].the(&:even?) # => 2
[1, 2, 3, 4].the(&:even?) # >> error
[1, 3].the(&:even?) # >> error
Using the usual block parameter, [1,2,3].the{|x| x.even?} could be read as "the x (out of [1, 2, 3]) such that x is even." If such x does not uniquely exist, this expression is uninterpretable.
Updated by Dan0042 (Daniel DeLorme) over 5 years ago
Actions
#27
[ruby-core:99772]
Hmmm, just now I realized there's a simple idiom that's roughly equivalent to one/single
[1,2].inject{break} #=> nil
[1,2].inject{raise} #=> error
[1].inject{break} #=> 1
[1].inject{raise} #=> 1
[].inject{break} #=> nil
[].inject{raise} #=> nil (instead of error)
Updated by Eregon (Benoit Daloze) over 5 years ago
Actions
#28
[ruby-core:99778]
matz (Yukihiro Matsumoto) wrote in #note-10:
Hmm, I don't like the name
single.
matz (Yukihiro Matsumoto) wrote in #note-17:
I don't like
onlyeither since these names do not describe the behavior.
Could you explain why?
I think single as in "return a single element or error out" is the best name here, and the most intuitive.
If I want a random element, then #sample already exists, so I don't think there would be any confusion to what Array#single or Enumerable#single would do.
array.only reads weirdly to me. array.single is so much nicer, no?
Updated by shan (Shannon Skipper) over 5 years ago
Actions
#29
[ruby-core:100008]
How about #sole since it means one and only and is concise?
[].sole
#!> SoleError: empty Array when single value expected (contains 0, expected 1)
Set.new.sole
#!> SoleError: empty Set when single value expected (contains 0, expected 1)
[41, 42, 43].sole
#!> SoleError: multiple values in Array when just one expected (contains 3, expected 1)
[42].sole
#=> 42
Or #one_and_only, but it's more wordy.
Updated by nobu (Nobuyoshi Nakada) over 5 years ago
Actions
#30
[ruby-core:100128]
Dan0042 (Daniel DeLorme) wrote in #note-25:
If collection is empty and a block was given, returns the block's return value:
I really think the block form should be like find/select
[1,2,3].one{ _1.even? } #=> 2 [1,2,3,4].one{ _1.even? } #=> error [1,2,3,4].one(nil){ _1.even? } #=> nil
It looks close to Enumerable#one? which counts truthy values only, but has a different semantics.
Updated by mame (Yusuke Endoh) over 5 years ago
Actions
#31
[ruby-core:100129]
A practical use case: When scraping a HTML document or something, sometimes we assume that an array length is 1.
nodes = html_node.children.select {|node| node.name == "table" }
raise if nodes.size == 1
the_node_i_want = nodes.first
The raise is needed for the case where my assumption is wrong.
This proposal makes it a bit helpful:
the_node_i_want = html_node.children.select {|node| node.name == "table" }.sole
Updated by nobu (Nobuyoshi Nakada) over 5 years ago
Actions
#32
[ruby-core:100280]
What about pattern matching?
case []; in [a]; p a; end #=> NoMatchingPatternError ([])
case [1]; in [a]; p a; end #=> 1
case [1,2]; in [a]; p a; end #=> NoMatchingPatternError ([1, 2])
Updated by shan (Shannon Skipper) over 5 years ago
Actions
#33
[ruby-core:100316]
For Arrays, pattern matching does seem like a fair solution. Wouldn't that not work for other Enumerable collections?
Set.new([42]) in [one] #!> NoMatchingPatternError (#<Set: {42}>)
It seems an Enumerable method would be more slick and nice for method chaining.
Set.new([42]).sole #=> 42
Set.new([42]).sole.digits #=> [2, 4]
Updated by mame (Yusuke Endoh) over 4 years ago
Actions
#34
- Related to Feature #18135: Introduce Enumerable#detect_only added
Updated by meisel (Michael Eisel) over 4 years ago
Actions
#35
[ruby-core:105124]
+1 for this, I've needed it in many cases, generally where I have to select an element from a set and there's no stable/documented way of doing this. So, I find some criteria that seem to work, but would like to protect against my criteria being wrong or invalidated by future changes. In the past, I've needed it for sets like sibling directories and sibling XML nodes.
As for the name, I think #take_only would be another reasonable option
Updated by mame (Yusuke Endoh) about 2 months ago
Actions
#36
[ruby-core:124422]
I've only just learned that ActiveSupport introduced Enumerable#sole back in 2020.
https://github.com/rails/rails/pull/40914
I wish this were available in the core too.
Updated by Eregon (Benoit Daloze) about 2 months ago
1Actions
#37
[ruby-core:124432]
+1 for sole (given Matz didn't like single and only).
It's clear and obvious what it does.
We could also allow it to take a block to address #18135 too:
enumerable.sole { condition(it) }
# same as
enumerable.select { condition(it) }.sole
# but more efficient (avoids Array allocation & just raise when condition matches 2 elements vs executing it on remaining elements needlessly)
one sounds find too, and seems consistent with the existing one?.
@nobu (Nobuyoshi Nakada) had a concern in https://bugs.ruby-lang.org/issues/13683#note-30 but I am not sure I understand it:
It looks close to
Enumerable#one?which counts truthy values only, but has a different semantics.
I guess it's about the form without a block enum.one vs enum.one?, [nil].one # => nil (= success) vs [false].one? # => false (= failure).
It's a good point, that would be confusing (because one? has a "default block" of { it } while this feature would have a "default block" of { true }).
If collection is empty and a block was given, returns the block's return value:
I wouldn't expect that, the block if any is accepted would be for find/select, not for default value.
"single" etc is an assertion there is a single element matching something, it should always raise if empty or no matching element.
Updated by headius (Charles Nutter) about 2 months ago
Actions
#38
[ruby-core:124436]
I don't like #sole as the method name but I can't quite explain why. I'd rather have #single or #singleton (The mathematical term for a set of one) or a two word #single_element or #one_only.
How about #one! or similar to indicate it must be one element?
Updated by zverok (Victor Shepelev) about 2 months ago
Actions
#39
[ruby-core:124439]
How about #one! or similar to indicate it must be one element?
I think Ruby's core agreement is ! indicates the methods that change the receiver (strip/strip!), so unless we plan to introduce Rails-y agreement with it designating "dangerous" method (save/save!), this wouldn't be appropriate.
I also feel weird about "sole" (I rarely see this word used anywhere in APIs or "simplified" engineering English), but so far, considering Matz vetoed single and only, and there are counter-arguments for one, this seems like the strongest contender.
The idea of a longer, more descriptive name doesn't sit right with me either; that's uncharacteristic for "simple" APIs.
Updated by headius (Charles Nutter) about 2 months ago
Actions
#40
[ruby-core:124442]
zverok (Victor Shepelev) wrote in #note-39:
How about #one! or similar to indicate it must be one element?
I think Ruby's core agreement is
!indicates the methods that change the receiver (strip/strip!), so unless we plan to introduce Rails-y agreement with it designating "dangerous" method (save/save!), this wouldn't be appropriate.
Ruby also uses it other places, like exit! and kill!, OpenSSL's generate_key!, Date's new!. It's also in English a way to emphasize the previous statement... so "one!" meaning "one and only one!".
I also feel weird about "sole" (I rarely see this word used anywhere in APIs or "simplified" engineering English), but so far, considering Matz vetoed
singleandonly, and there are counter-arguments forone, this seems like the strongest contender.
I could perhaps be convinced about "solitary" or other accepted terms for "one and only one" but "sole" does not feel right at all.
Updated by matz (Yukihiro Matsumoto) about 1 month ago
Actions
#41
[ruby-core:124525]
I now agree with having a method with proposed behavior. We have to pick a name for it.
I don't like single. I have no strong opinion for/against sole. But I don't want to introduce a new exception class dedicated to this sole method (as #sole in ActiveSupport does).
The other candidates are:
- one!
- only
- lone
- singular
AI strongly suggested only. I am still wondering. Any opinion?
One possible solution is providing our version of sole that raises ArgumentError, only if AcriveSupport would define SoleItemExpectedEror = ArgumentError or something similar.
Matz.
Updated by byroot (Jean Boussier) about 1 month ago
Actions
#42
[ruby-core:124530]
if AcriveSupport would define SoleItemExpectedEror = ArgumentError or something similar.
We can do that, that's no problem.
If Enumerable#sole lands in Ruby, I'll take care of handling any backward compatibility issue in Rails/Active Support.
Updated by Dan0042 (Daniel DeLorme) about 1 month ago
Actions
#43
[ruby-core:124536]
Please consider a method that returns nil instead of raising an exception. Exceptions should not be used for control flow.
Which one is better?
#method returning nil
val = collection.one{ ... } #match or nil
val = collection.one{ ... } or raise MyError #match or error
#method raising error
val = collection.one!{ ... } rescue nil #match or nil
val = collection.one!{ ... } #match or error
imho returning nil is better; we pay the cost of an exception only when we need it.
Of course I'm not against having both.
Updated by byroot (Jean Boussier) about 1 month ago
1Actions
#44
[ruby-core:124537]
The exception here isn't meant to be used for control flow any more than KeyError is when you use Hash#fetch.
It's used as some sort of assertion, you wouldn't typically rescue it.
Updated by jeremyevans0 (Jeremy Evans) about 1 month ago
1Actions
#45
[ruby-core:124539]
matz (Yukihiro Matsumoto) wrote in #note-41:
One possible solution is providing our version of
solethat raisesArgumentError, only if AcriveSupport would defineSoleItemExpectedEror = ArgumentErroror something similar.
My understanding is that ArgumentError should be used for invalid arguments. Since the method doesn't accept arguments, using ArgumentError for this feels wrong to me. If we do not want to introduce an exception subclass for this, I think RangeError would be better than ArgumentError, because the issue is the the size/range of the receiver is not as expected.
Updated by ufuk (Ufuk Kayserilioglu) about 1 month ago
Actions
#46
[ruby-core:124540]
@Dan0042 (Daniel DeLorme) If the proposed method isn't going to raise an exception, then how would one disambiguate between a nil result because the collection has a single entry which is nil and a nil result since the collection has (for example) 2 elements?
If someone is calling collection.one then they would be expecting to find a single element in the collection. Failure of that expectation would be an exceptional case, which needs an exception.
Updated by Dan0042 (Daniel DeLorme) about 1 month ago
ยท Edited
Actions
#47
[ruby-core:124541]
@byroot (Jean Boussier) it depends on the use case. Yes sometimes it's an assertion that should raise an error, but at other times we want to find the single element, and do something only if found, not raise an error.
@ufuk (Ufuk Kayserilioglu) the same way you disambiguate when #find returns nil. Or #delete or #delete_at or #[] or #bsearch or #first, etc. In other words Ruby is designed so that nil is equivalent to undefined and this is the way it normally works for any method that returns one of the elements of the collection. #fetch is a notable exception.
And as I said I'm not against having both return-nil and raise-error versions, but I do consider that return-nil is the more relevant one.
Updated by mame (Yusuke Endoh) about 1 month ago
Actions
#48
[ruby-core:124543]
Enumerable#sole is a method that should only be used when the Enumerable has only one element. Using it in other cases (0 or 2+ elements) is considered a bug, or literally "exceptional", so raising an exception makes perfect sense.
In the dev meeting, when we consider the name Enumerable#one!, I briefly mentioned Enumerable#one, a moderate variant that returns nil instead of raising an exception. But no one seriously considered it because we can find no use case for it.
Updated by Anonymous about 1 month ago
Actions
#49
Updated by Eregon (Benoit Daloze) about 1 month ago
Actions
#50
[ruby-core:124546]
I think for the use case of "check if a single value" from @Dan0042 (Daniel DeLorme) then ary.first if ary.size == 1 or so is good enough.
I agree the new method here is meant to assert and the usefulness of it comes from the exception if it unexpectedly doesn't hold.
value = ary.size == 1 ? ary.first : raise(SomeError) is of course possible but that's quite verbose and I think a pattern worth capturing as a core method.
Updated by Eregon (Benoit Daloze) about 1 month ago
Actions
#51
[ruby-core:124547]
@baweaver (Brandon Weaver) FYI your reply didn't work on Redmine, it shows an empty comment by Anonymous, so I'd suggest you add on Redmine for future comments to workaround that.
The comment is:
I would advocate for using a
!on the end of whatever we pick to signify it does something "dangerous" (e.g. exception) just as a warning for users.
This is not the case for core methods, core methods only have a ! if it's a more dangerous version of a non-! method, which is not the case here if we add a single method.
Updated by Dan0042 (Daniel DeLorme) about 1 month ago
Actions
#52
[ruby-core:124564]
mame (Yusuke Endoh) wrote in #note-48:
But no one seriously considered it because we can find no use case for it.
Uh, seriously? I gave an example in #note-16 and we have 11 other similar instances in our codebase. But none that raise an error. Pretty often used as collection.compact.uniq.single where we use it as default value for a new record if there is only one. Or, let's say search for product "ABC" and if there is only one match then redirect to it directly, otherwise display the search results. Anyway, I'm just giving my honest feedback. If if turns out the method raises an error, it's no big deal, I'll just keep using our own #single.
Eregon (Benoit Daloze) wrote in #note-50:
then
ary.first if ary.size == 1or so is good enough.
That logic doesn't work at all. Of course it's "good enough" but in that case raise if ary.size != 1 would also be "good enough".
Updated by headius (Charles Nutter) about 1 month ago
Actions
#53
[ruby-core:124567]
Of the proposed options I still like one! best. It conveys both returning a single element and enforcing that there's exactly one.