Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple warnings #1184

Closed
fornellas opened this issue May 11, 2016 · 9 comments
Closed

Multiple warnings #1184

fornellas opened this issue May 11, 2016 · 9 comments

Comments

@fornellas
Copy link

Complete Description of Issue

Sequel gives a lot of warnings while running. I usually execute my tests with warnings enabled, and Sequel is giving a lot of unneeded output. They seem harmless, but surely are noisy.

Simplest Possible Self-Contained Example Showing the Bug

$ irb -rsequel -w
/home/fornellas/local/gems/23/gems/wirble-0.1.3/lib/wirble.rb:410: warning: assigned but unused variable - nocol
/home/fornellas/local/gems/23/gems/wirble-0.1.3/lib/wirble.rb:440: warning: assigned but unused variable - colors
/home/fornellas/local/gems/23/gems/wirble-0.1.3/lib/wirble.rb:78: warning: instance variable @verbose not initialized
/home/fornellas/local/gems/23/gems/awesome_print-1.6.1/lib/awesome_print/core_ext/array.rb:19: warning: method redefined; discarding old -
/home/fornellas/local/gems/23/gems/awesome_print-1.6.1/lib/awesome_print/core_ext/array.rb:19: warning: method redefined; discarding old &
>> Sequel.extension :migration
=> [:migration]
>> Sequel.sqlite('/tmp/a')
=> #<Sequel::SQLite::Database: {:adapter=>:sqlite, :database=>"/tmp/a"}>
>> db = Sequel.sqlite('/tmp/a')
=> #<Sequel::SQLite::Database: {:adapter=>:sqlite, :database=>"/tmp/a"}>
>> Sequel::Migrator.run(db, '/tmp/m')
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/actions.rb:71: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/query.rb:80: warning: instance variable @columns not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/sql.rb:1494: warning: instance variable @skip_symbol_cache not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/misc.rb:85: warning: instance variable @frozen not initialized
/home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/dataset/sql.rb:1494: warning: instance variable @skip_symbol_cache not initialized
Sequel::Migrator::Error: No target version available, probably because no migration files found or filenames don't follow the migration filename convention
    from /home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/extensions/migration.rb:525:in `initialize'
    from /home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/extensions/migration.rb:397:in `new'
    from /home/fornellas/local/gems/23/gems/sequel-4.34.0/lib/sequel/extensions/migration.rb:397:in `run'
    from (irb):4
    from /opt/ruby-2.3.0/bin/irb:11:in `<main>'
>> 
@jeremyevans
Copy link
Owner

The uninitialized instance variable warnings are expected, Sequel purposely does not initialize instance variables for performance reasons. I may consider fixing other warnings, though the example you gave includes only uninitialized instance variable warnings.

I've proposed a ruby API for filtering warnings (https://bugs.ruby-lang.org/issues/12299), which would allow Sequel to be less noisy in verbose mode. It should be discussed at the ruby developers meeting next week. Hopefully matz will accept my proposal or an approach that offers comparable functionality.

@fornellas
Copy link
Author

I understand your proposal for selective warnings, however, not initializing variables due to performance, raises some doubt in my head. How much performance exactly are we gaining? If we benchmark a real world application with vanilla Sequel, and a patched Sequel (to initialize all variables), how much performance do we loose (%)? In general, other projects consider warnings to be "not good", and usually accept patches to suppress them. I imagine this performance argument must be very heavy to consider it different in Sequel.

In the meantime, I used the code below in my project, to suppress warnings around every Sequel call (which is annoying). Might be useful to other users. The first one suppress warnings in code inside given block, the second one, can be used to convert an Enumerator to another Enumerator with suppressed warnings (useful for data sets).

  # Execute given block with <tt>$VERBOSE = false</tt>.
  def no_verbose
    original_verbose = $VERBOSE
    begin
      $VERBOSE = false
      yield
    ensure
      $VERBOSE = original_verbose
    end
  end

  # Receives an Enumerable from given block, and returns a new Enumerable, that have with <tt>$VERBOSE = false</tt> when executing. Ex:
  #  no_verbose_enum{[1,2,3].to_enum}.each{|e| puts e}
  def no_verbose_enum
    enum = no_verbose { yield }
    Enumerator.new do |yilder|
      loop do
        element = nil
        begin
          no_verbose { element = enum.next }
        rescue StopIteration
          break
        else
          yilder << element
        end
      end
    end
  end

@jeremyevans
Copy link
Owner

The performance overhead of initializing instance variables to nil is significant, both in the time it takes to do the initialization and the extra memory it uses. See https://bugs.ruby-lang.org/issues/10396 for a benchmark.

@jeremyevans
Copy link
Owner

Also, if you want to want to see what's involved in patching Sequel to remove verbose warnings, I had a diff to do so (now a couple years old): https://groups.google.com/forum/#!searchin/sequel-talk/warning/sequel-talk/9aehjtVM6II/6BpInBub1LcJ

@fornellas
Copy link
Author

OK, I understand there is a pontual performance impact, I am not doubting that at all. I meant how much does it affect overall performance in a real world application. Is this variable initialization any bottleneck? Does it add 15% more CPU time for any request made?

To fully form an opinion, I'd have to remake the no-warnings patch, run some (close to) real world benchmarks over Sequel within an application, and plot the results. I can do that, no problem, but only if it would be relevant to changing the project direction over warnings. I am guessing performance impact overall is gonna be tiny, and that the value of having warnings enabled would be greater than suppressing them in such case, as warnings can help spot programming mistakes.

@jeremyevans
Copy link
Owner

Initializing instance variables to nil had a measureable difference when retrieving large datasets when I last benchmarked it. I forget the exact numbers, but I think between 5-15%, depending on which model plugins were in use. Anything above 0.1% I would consider unacceptable from a performance perspective. Additionally, initializing instance variables to nil clutters the code base. The value of uninitialized instance variable warnings in Sequel is tiny, I am not sure there has every been a bug in Sequel due to a misnamed instance variable.

I initially proposed from removing the uninitialized instance variable warning from ruby completely, which would provide a substantial speedup by itself. Alas, that was not accepted, so I'm working on making it easy to filter warnings, so that when using Sequel in future versions of ruby, uninitialized instance variable warnings in Sequel will not be emitted, but you can still have uninitialized instance variable warnings in your application code.

@fornellas
Copy link
Author

5-15% is really high! That being, fixing the warnings would solve one problem, but create other, tough choice. I do get your point.

@Aupajo
Copy link

Aupajo commented Aug 31, 2019

The performance issue is a fair one, but if you're willing to make the trade-off for your test environment, I ended up doing this:

# spec/support/sequel.rb
SEQUEL_GEM_PATH = Gem.loaded_specs['sequel'].full_gem_path

Warning.class_eval do
  alias original_warn warn

  def warn(message)
    original_warn(message) unless message.match?(SEQUEL_GEM_PATH)
  end
end

@flash-gordon
Copy link
Contributor

@Aupajo and Jeremy created a gem for automating this https://github.com/jeremyevans/ruby-warning :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants