https://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112021-12-01T17:08:45ZRuby Issue Tracking SystemRuby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=949972021-12-01T17:08:45ZEregon (Benoit Daloze)
<ul></ul><p>I think this could be useful.<br>
I've seen several cases like this, notably I remember <a href="https://github.com/ffi/ffi/blob/master/lib/ffi.rb" class="external">https://github.com/ffi/ffi/blob/master/lib/ffi.rb</a>.<br>
There is a workaround there: <code>(RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [20, 1, 0]) >= 0</code> since RubyGems might not be loaded yet at that point.<br>
That's not really pretty, so a builtin <code>Version</code> seems nicer.</p>
<p>One issue I could imagine is different version conventions and how to compare them.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=949982021-12-01T17:47:12Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<ul></ul><p>Eregon (Benoit Daloze) wrote in <a href="#note-1">#note-1</a>:</p>
<blockquote>
<p>One issue I could imagine is different version conventions and how to compare them.</p>
</blockquote>
<p>Opportunity for standardization? :) RubyGems with their version checking are doing that anyway.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=949992021-12-01T17:55:24Zdeivid (David Rodríguez)
<ul></ul><p>My opinion is that the right place for this functionality is RubyGems and that adding/duplicating it as builtin functionality because someone might need it before rubygems is loaded, or while using <code>--disable-gems</code> is overkill.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950002021-12-01T20:36:25ZEregon (Benoit Daloze)
<ul></ul><p>Note that for default gems (which ffi is on jruby/truffleruby) it's also not possible to use RubyGems, so I think there is a non-trivial amount of cases.</p>
<p>Additionally, if people use bundler standalone mode, there is also no RubyGems loaded (or it's suboptimal to load it).</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950032021-12-01T21:24:22Zdeivid (David Rodríguez)
<ul></ul><p>Yeah, I still think it's completely overkill, and people will be confused because we will have two different things that do the same thing.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950062021-12-01T22:59:47Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<ul></ul><p>RubyGems could adopt this API and slowly phase out its own version.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950182021-12-02T07:47:14Zpocke (Masataka Kuwabara)
<ul></ul><p><code>::Version</code> will be conflict with <code>optparse</code>'s convention. Probably we need to consider the naming.<br>
ref: <a href="https://github.com/ruby/ruby/blob/fe506d7945788f4c3243e9ec25c20c5dbd315073/lib/optparse.rb#L1208-L1213" class="external">https://github.com/ruby/ruby/blob/fe506d7945788f4c3243e9ec25c20c5dbd315073/lib/optparse.rb#L1208-L1213</a></p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950212021-12-02T08:10:39Znaruse (Yui NARUSE)naruse@airemix.jp
<ul><li><strong>Related to</strong> <i><a class="issue tracker-2 status-2 priority-4 priority-default" href="/issues/17684">Feature #17684</a>: Remove `--disable-gems` from release version of Ruby</i> added</li></ul> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950222021-12-02T08:11:53Znaruse (Yui NARUSE)naruse@airemix.jp
<ul><li><strong>Is duplicate of</strong> <i><a class="issue tracker-2 status-6 priority-4 priority-default closed" href="/issues/5861">Feature #5861</a>: String#version_compare</i> added</li></ul> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950242021-12-02T08:16:34Znaruse (Yui NARUSE)naruse@airemix.jp
<ul></ul><p>If you are saying we want to use some rubygems feature with --disable-gems, we need to raise <a class="issue tracker-2 status-2 priority-4 priority-default" title="Feature: Remove `--disable-gems` from release version of Ruby (Assigned)" href="https://bugs.ruby-lang.org/issues/17684">#17684</a> again.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950262021-12-02T09:56:46Zdeivid (David Rodríguez)
<ul></ul><blockquote>
<p>RubyGems could adopt this API and slowly phase out its own version.</p>
</blockquote>
<p>Thanks for bringing that up. The more I think about it, the more I dislike it. I don't think version comparison is common enough to be something builtin to core, let alone if it's only to satisfy the needs of a handful of default gems (only ffi has been mentioned so far). It feels to me that in order to save one line of code in ffi, I have to go through the trouble of slowly phasing out what's probably the most commonly used rubygems constant in the wild. Definitely not a fan :sweat_smile:.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950272021-12-02T10:35:07ZEregon (Benoit Daloze)
<ul></ul><p><code>String#version_compare</code> (<a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: String#version_compare (Rejected)" href="https://bugs.ruby-lang.org/issues/5861">#5861</a>) would likely be a much less invasive way to add this, and so probably better.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950282021-12-02T10:45:08Zdeivid (David Rodríguez)
<ul></ul><p>That feature request was rejected by Matz because of not being common enough, and nothing seems to have changed in that regard.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950332021-12-02T15:28:30Zaustin (Austin Ziegler)halostatue@gmail.com
<ul></ul><p>deivid (David Rodríguez) wrote in <a href="#note-11">#note-11</a>:</p>
<blockquote>
<blockquote>
<p>RubyGems could adopt this API and slowly phase out its own version.</p>
</blockquote>
<p>Thanks for bringing that up. The more I think about it, the more I dislike it. I don't think version comparison is common enough to be something builtin to core, let alone if it's only to satisfy the needs of a handful of default gems (only ffi has been mentioned so far). It feels to me that in order to save one line of code in ffi, I have to go through the trouble of slowly phasing out what's probably the most commonly used rubygems constant in the wild. Definitely not a fan :sweat_smile:.</p>
</blockquote>
<p>I have at least two libraries that I maintain using the <code>Gem::Version</code> API for feature enablement or back-port support. Some libraries that I have used for projects set <code>VERSION = Gem::Version.new('1.2.3')</code>; at least some of the gems that I have used in the past <em>also</em> use the version API in the same way that I do.</p>
<p>People reach for <code>Gem::Version</code> because it’s the most feature-complete readily available semver library for Ruby. As a comparison, Elixir <em>does</em> provide a <code>Version</code> module as part of core.</p>
<p>If we don’t want to add a <code>::Version</code> constant to core, then perhaps the <em>best</em> thing to do would be for <code>Gem::Version</code> to be made available <em>separately</em> from the rest of RubyGems, possibly importing it into core (this has the benefit of <em>not</em> requiring an API change for anything that <em>uses</em> it). Or maybe (and this is a bit of a bootstrap problem), <code>Gem::Version</code> could be packaged as its own gem for people to import separately if they need gem versioning.</p>
<p>This isn’t a <em>frequent</em> problem, but I disagree that it’s "not common enough". I have <em>no clue</em> what would happen with the gems that I maintain (<code>mime-types</code> is perhaps the easiest version to test) if run with <code>--disable-gems</code>. I think that this is worth adding to core.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950352021-12-02T16:11:19Zdeivid (David Rodríguez)
<ul></ul><p>I'm definitely aware that this is used for what you point out. But most gem authors just use it and don't worry about "what if rubygems is not available?", which I think it's reasonable because rubygems is part of ruby and they are developing a gem after all.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950382021-12-02T16:32:12Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<ul></ul><p>There is probably more to this issue.</p>
<ol>
<li>On the first place, I'd love if everybody used introspection instead of version checks. We would not need to have this conversation. But honestly, I don't really know how to detect the kwargs.</li>
<li>Ruby used to have simple version comparison up until 2.1.10. The string comparison worked just fine. Nevertheless "-preview1" would break it anyway.</li>
<li>I don't know what is suggested way to compare Ruby versions since Ruby 2.1.10. <code>String#version_compare</code> would be certainly quite easy interface. Or RUBY_VERSION could provide some operator for version comparisons. <code>Gem::Version.new("2.6.18")<=>Gem::Version.new("2.6.3")</code> was pointed out already in <a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: String#version_compare (Rejected)" href="https://bugs.ruby-lang.org/issues/5861">#5861</a> but that means the third party dependency.</li>
<li>If the third party dependency is deemed OK, then it should be accompanied by <code>require "rubygems/version"</code> to ensure it is available. But that on itself won't work and <code>require "rubygems"</code> is needed. I don't think that it can be assumed that dependencies are loaded.</li>
</ol> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950392021-12-02T16:42:39Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<ul></ul><p>deivid (David Rodríguez) wrote in <a href="#note-15">#note-15</a>:</p>
<blockquote>
<p>But most gem authors</p>
</blockquote>
<p>This is OT, but just FTR, I might be considered "gem author", but I am Ruby developer on the first place. RubyGems are mostly convenient way of code distribution, but there are other ways (e.g. <code>git clone</code> or RPM/DNF on my platform).</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950402021-12-02T16:50:45Zaustin (Austin Ziegler)halostatue@gmail.com
<ul></ul><p>deivid (David Rodríguez) wrote in <a href="#note-15">#note-15</a>:</p>
<blockquote>
<p>I'm definitely aware that this is used for what you point out. But most gem authors just use it and don't worry about "what if rubygems is not available?", which I think it's reasonable because rubygems is part of ruby and they are developing a gem after all.</p>
</blockquote>
<p>Yet there's people who use <code>--disable-gems</code> for various reasons, yet might also use a standalone bundle. I just tried this and I <em>do</em> get an uninitialized constant error with <code>--disable-gems</code>. I know that gem authors treat Rubygems as a given, but it feels…iffy to me that we depend on this this way. I did just see that <code>Gem::Version</code> does not get defined in an idempotent way, as it is declared with <code>class Gem::Version</code> and not <code>class Gem; class Version</code>: <code>ruby --disable-gems -rrubygems/version -e 'p Gem::Version'</code> results in <code>uninitialized constant Gem</code>.</p>
<p>At any rate, I am using Elixir much more often these days, where I <em>do</em> have a <code>Version</code> module built-in for those (admittedly rare) cases where I need version comparison—and it is <em>really</em> nice to have something readily available as part of the core.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950412021-12-02T16:54:07Zdeivid (David Rodríguez)
<ul></ul><p>Of course, but I believe most people who need this are gem authors, and most gem authors use rubygems. People developing apps usually support a single version of gems or ruby, so generally don't need this kind of feature? I think most Ruby developers assume they can use <code>Gem::Version</code> freely, because Rubygems is normally available by default.</p>
<p>Anyways, I think my opinion is pretty clear so I'll refrain from commenting further.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950422021-12-02T16:56:19Zdeivid (David Rodríguez)
<ul></ul><p>Sorry <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/74">@austin (Austin Ziegler)</a>, I was actually replying to <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/703">@vo.x (Vit Ondruch)</a> in my previous comment, but our comments crossed. Anyways, I don't have much to add, really!</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=950812021-12-03T03:56:41Zunasuke (Yusuke Nakamura)
<ul></ul><p>I think it is useful for not just gem authors but also application developers.<br>
In my known case of providing an SDK and API as service, version string compare is often used in parsing SDK version string on request from SDK to API server.<br>
Gem::Version is commonly used for comparing "semantic version"-ed version string in that situation. Because it can use without any other gem installed. But that is not "Gem". It brings tiny context confusion.</p>
<p>If I can use the same function with <code>::Version</code>, it's useful. Not that I'm against it, but I am not sure if it's worth introducing this as a standard library because it might require a lot of work to resolve all of the above concerns.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951642021-12-06T09:02:22Zdeivid (David Rodríguez)
<ul></ul><p>Thinking a bit more about this, current <code>Gem::Version</code> functionality seems quite independent, so there may be a way to provide this feature that's also low friction for rubygems maintainers.</p>
<p>Something like <a href="https://github.com/rubygems/rubygems/pull/5136" class="external">https://github.com/rubygems/rubygems/pull/5136</a> would already address the "I don't want to load all of rubygems just to compare some versions" concern. But if we extracted rubygems <code>version.rb</code> file to a new default gem, that would provide the same functionality through the <code>::Version</code> class for users that explicitly <code>require "version"</code>, also addressing the "<code>Gem::Version</code> is confusing for some version usages not related to gems" concern. Nothing would have to change for us in rubygems, we would need to vendor <code>version.rb</code> under the <code>Gem</code> namespace like we do for other default gems, which is exactly what we are already doing.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951662021-12-06T12:36:33ZEregon (Benoit Daloze)
<ul></ul><p>deivid (David Rodríguez) wrote in <a href="#note-22">#note-22</a>:</p>
<blockquote>
<p>Something like <a href="https://github.com/rubygems/rubygems/pull/5136" class="external">https://github.com/rubygems/rubygems/pull/5136</a> would already address the "I don't want to load all of rubygems just to compare some versions" concern.</p>
</blockquote>
<p>Unfortunately this does not work if RubyGems is loaded lazily via <code>autoload :Gem, 'rubygems'</code> (it will load all of RubyGems on <code>require 'rubygems/version'</code>).</p>
<p>And also this seems quite confusing if the <code>Gem</code> constant is defined but all the constants/classes under <code>Gem</code> are not there and would be <code>NameError</code> when accessing them, unless <code>require 'rubygems'</code> is done before those accesses:</p>
<pre><code>$ ruby --disable-gems -e 'require "rubygems/version"; p Gem::Version; p Gem::Specification'
Gem::Version
-e:1:in `<main>': uninitialized constant Gem::Specification (NameError)
</code></pre>
<p>For this reason, IMHO that PR should be reverted.</p>
<blockquote>
<p>But if we extracted rubygems <code>version.rb</code> file to a new default gem, that would provide the same functionality through the <code>::Version</code> class for users that explicitly <code>require "version"</code>, also addressing the "<code>Gem::Version</code> is confusing for some version usages not related to gems" concern. Nothing would have to change for us in rubygems, we would need to vendor <code>version.rb</code> under the <code>Gem</code> namespace like we do for other default gems, which is exactly what we are already doing.</p>
</blockquote>
<p>That seems a great idea to me.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951672021-12-06T12:49:56Zdeivid (David Rodríguez)
<ul></ul><blockquote>
<p>And also this seems quite confusing if the Gem constant is defined but all the constants/classes under Gem are not there and would be NameError when accessing them, unless require 'rubygems' is done before those accesses:</p>
</blockquote>
<p>I mean, of course, right? What else would you expect? Isn't that the whole point?</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951682021-12-06T12:52:18Zdeivid (David Rodríguez)
<ul></ul><p>To clarify, won't users of <code>--disable-gems</code> will expect that nothing under <code>Gem</code> is defined except for the explicitly required <code>rubygems/version</code>? Isn't that what they want?</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951692021-12-06T12:56:32ZEregon (Benoit Daloze)
<ul></ul><p>deivid (David Rodríguez) wrote in <a href="#note-24">#note-24</a>:</p>
<blockquote>
<p>I mean, of course, right? What else would you expect? Isn't that the whole point?</p>
</blockquote>
<p>Not really, I think the whole point is to have a version API without needing to load RubyGems and working even if RubyGems is not loaded (<code>--disable-gems</code>, Bundler standalone, etc).<br>
The side-effect of breaking any access under <code>Gem</code> in some cases is IMHO bad enough that that PR is not worth it.<br>
It'll break any <code>defined?(Gem)</code> usage, etc.<br>
We've had empty YAML, Date and other modules defined in the past, it's really confusing and IMHO should be avoided at all costs.</p>
<p>The <code>version</code> default gem idea OTOH has none of these problems, so I think that's the way to go for this issue.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951702021-12-06T13:16:02Zdeivid (David Rodríguez)
<ul></ul><p>I disagree that this will "break" anything, but I'll revert for now until we gather some more opinions on my better idea.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=951852021-12-06T20:30:31Zdeivid (David Rodríguez)
<ul></ul><p>We reverted it for now.</p> Ruby master - Feature #18376: Version comparison APIhttps://bugs.ruby-lang.org/issues/18376?journal_id=957362021-12-30T10:33:01Zjanosch-x (Janosch Müller)
<ul></ul><p>pocke (Masataka Kuwabara) wrote in <a href="#note-7">#note-7</a>:</p>
<blockquote>
<p><code>::Version</code> will be conflict with <code>optparse</code>'s convention. Probably we need to consider the naming.</p>
</blockquote>
<p>Maybe <code>Semver</code>?</p>
<p>This is a bit clunky but would arguably indicate the core functionality better than <code>Version</code>. (Or <code>SemVer</code>, but lower case "v" would match <code>Errno</code>, <code>Regexp</code>.)</p>