From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: poffice@blade.nagaokaut.ac.jp Delivered-To: poffice@blade.nagaokaut.ac.jp Received: from kankan.nagaokaut.ac.jp (kankan.nagaokaut.ac.jp [133.44.2.24]) by blade.nagaokaut.ac.jp (Postfix) with ESMTP id 0F77219C03DD for ; Thu, 26 Nov 2015 16:49:04 +0900 (JST) Received: from voscc.nagaokaut.ac.jp (voscc.nagaokaut.ac.jp [133.44.1.100]) by kankan.nagaokaut.ac.jp (Postfix) with ESMTP id 12D29B5D891 for ; Thu, 26 Nov 2015 17:20:11 +0900 (JST) Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by voscc.nagaokaut.ac.jp (Postfix) with ESMTP id 8515C18CC7E4 for ; Thu, 26 Nov 2015 17:20:11 +0900 (JST) Received: from [221.186.184.76] (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 8157612050C; Thu, 26 Nov 2015 17:20:09 +0900 (JST) X-Original-To: ruby-core@ruby-lang.org Delivered-To: ruby-core@ruby-lang.org Received: from o10.shared.sendgrid.net (o10.shared.sendgrid.net [173.193.132.135]) by neon.ruby-lang.org (Postfix) with ESMTPS id 0E3D01204E2 for ; Thu, 26 Nov 2015 17:20:05 +0900 (JST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sendgrid.me; h=from:to:references:subject:mime-version:content-type:content-transfer-encoding:list-id; s=smtpapi; bh=lwO+zqH1VaCkEtPiRwQkFbl2x2E=; b=OLc+c4CSVW7XMm0ny/ zIhHW7ip/u8IkEPt0COGWs4kQmPcDFOWrpkzPyocRcngDUEU5WRn+7Xj+Aaja6+o qOhjHOzDOAKFy1uJyB4qEKMkgixVCPigoyJHIocVD1S3tL1WkX5m+3Bxs9oKfTDI oPS/OngGvIOo05L9Ux6LkZ73g= Received: by filter0535p1mdw1.sendgrid.net with SMTP id filter0535p1mdw1.24622.5656C0B27 2015-11-26 08:20:02.432872976 +0000 UTC Received: from herokuapp.com (ec2-54-204-208-222.compute-1.amazonaws.com [54.204.208.222]) by ismtpd0004p1iad1.sendgrid.net (SG) with ESMTP id 8yhL-2QnSqu6X_cC7b4amA for ; Thu, 26 Nov 2015 08:20:02.294 +0000 (UTC) Date: Thu, 26 Nov 2015 08:20:02 +0000 From: shugo@ruby-lang.org To: ruby-core@ruby-lang.org Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Redmine-MailingListIntegration-Message-Ids: 46375 X-Redmine-Project: ruby-trunk X-Redmine-Issue-Id: 11704 X-Redmine-Issue-Author: danielpclark X-Redmine-Issue-Assignee: matz X-Redmine-Sender: shugo X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-SG-EID: ync6xU2WACa70kv/Ymy4QrNMhiuLXJG8OTL2vJD1yS6STcsW+EuXnZFLo9P32ue6j7Zr8NxUo7YZBX rWydCEJ5dZ5ti42IwpFHnHcsDmD2ZB/svaeCOmVqsvSpYciDrAPlRxLYgHxf5kYmqMbdkL6JAwy0jn udCP9BhDA4Pf3s9CvxUHb2gO0cBA1u13mcFp X-ML-Name: ruby-core X-Mail-Count: 71696 Subject: [ruby-core:71696] [Ruby trunk - Bug #11704] [Assigned] Refinements only get "used" once in loop X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #11704 has been updated by Shugo Maeda. Status changed from Open to Assigned Assignee set to Yukihiro Matsumoto Daniel P. Clark wrote: > I wrote a benchmark for testing different ways of implementing a `uniq` method and I chose to do it using refinements. I looped over the results in the benchmark and refined the method with 6 different refinements which each worked. But the next iteration when `using` is called it doesn't re-refine with previously used refinements. Once refinements are activated by `using` in a specific order, the precedence of the refinements cannot be changed, because Refinements are not designed for such dynamic use. What do you think, Matz? ---------------------------------------- Bug #11704: Refinements only get "used" once in loop https://bugs.ruby-lang.org/issues/11704#change-55103 * Author: Daniel P. Clark * Status: Assigned * Priority: Normal * Assignee: Yukihiro Matsumoto * ruby -v: * Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN ---------------------------------------- Same results on Ruby 2.2.2 through Ruby 2.3.0dev (2015-11-18 trunk 52625) [x86_64-linux] I wrote a benchmark for testing different ways of implementing a `uniq` method and I chose to do it using refinements. I looped over the results in the benchmark and refined the method with 6 different refinements which each worked. But the next iteration when `using` is called it doesn't re-refine with previously used refinements. Example benchmark output on first iteration: ~~~ Array.new(200) !self.dup.uniq! 1.770000 0.010000 1.780000 ( 1.778248) Array.new(200) == uniq.length 1.860000 0.000000 1.860000 ( 1.866862) Array.new(200) == uniq.sort 2.580000 0.010000 2.590000 ( 2.584515) Array.new(200) each index 41.450000 0.080000 41.530000 ( 41.626149) Array.new(200) combination(2) 23.460000 0.060000 23.520000 ( 23.568865) Array.new(200) == self.uniq 1.900000 0.010000 1.910000 ( 1.909466) ~~~ After that the same methods did not get refined. ~~~ Array.new(210) !self.dup.uniq! 1.990000 0.000000 1.990000 ( 2.004269) Array.new(210) == uniq.length 2.030000 0.010000 2.040000 ( 2.032602) Array.new(210) == uniq.sort 1.990000 0.000000 1.990000 ( 1.999509) Array.new(210) each index 1.990000 0.010000 2.000000 ( 2.000181) Array.new(210) combination(2) 2.000000 0.000000 2.000000 ( 2.010159) Array.new(210) == self.uniq 2.000000 0.010000 2.010000 ( 2.009117) Array.new(220) !self.dup.uniq! 2.100000 0.010000 2.110000 ( 2.113701) Array.new(220) == uniq.length 2.070000 0.000000 2.070000 ( 2.075249) Array.new(220) == uniq.sort 2.090000 0.010000 2.100000 ( 2.102771) Array.new(220) each index 2.070000 0.000000 2.070000 ( 2.077393) Array.new(220) combination(2) 2.070000 0.010000 2.080000 ( 2.079561) Array.new(220) == self.uniq 2.100000 0.010000 2.110000 ( 2.110839) Array.new(230) !self.dup.uniq! 2.210000 0.000000 2.210000 ( 2.236008) Array.new(230) == uniq.length 2.160000 0.010000 2.170000 ( 2.166484) Array.new(230) == uniq.sort 2.140000 0.000000 2.140000 ( 2.150384) Array.new(230) each index 2.130000 0.010000 2.140000 ( 2.134572) Array.new(230) combination(2) 2.120000 0.000000 2.120000 ( 2.129683) Array.new(230) == self.uniq 2.130000 0.010000 2.140000 ( 2.137515) ~~~ I found no way to inspect what code was being used as refinements currently don't allow introspection (I have read the Refinement Specs https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/RefinementsSpec ). But I figure if I wanted to see what the refinement was I could write an additional method to document the current refinement in use. ~~~ruby module BooleanUniqWithEqualLength refine Array do def uniq? self.length == self.uniq.length end def which_refinement_uniq? "self.length == self.uniq.length" end end end ~~~ But introspection is not the issue I'm raising here. The issue is that you can only use the refinement once within the scope of the loop. Look at the benchmark results and see the first 6 are correct, and the following 3 times the output is lying about what refinement is being used. Here's the full benchmark code: ~~~ruby require 'securerandom' require 'benchmark' # written to allow 65,536 unique array items array_of_x = lambda {|x| SecureRandom.hex(x*2).scan(/..../) } module Refinements module BooleanUniqWithDupUniqBang refine Array do def uniq? !self.dup.uniq! end end end module BooleanUniqWithEqualLength refine Array do def uniq? self.length == self.uniq.length end end end module BooleanUniqWithEqualSort refine Array do def uniq? self.sort == self.uniq.sort end end end module BooleanUniqWithEachIndex refine Array do def uniq? self.each_with_index { |a,b| self.each_with_index { |c,d| next if b == d return false if a == c } } true end end end module BooleanUniqWithCombination refine Array do def uniq? self.combination(2).each {|a,b| return false if a == b} true end end end module BooleanUniqWithUniq refine Array do def uniq? self == self.uniq end end end end bench_reps = 10_000 bench = Benchmark.benchmark("\nTesting various ways of implementing :uniq? on Array\n(smaller numbers are better)\n\n",34) do |x| # Note doing anymore than one test per test type seems to wash the results into all things being equal. # Only the first test gives realistic numbers. [500].each do |qty| x.report("Array.new(#{qty}) !self.dup.uniq!") { using Refinements::BooleanUniqWithDupUniqBang bench_reps.times do array_of_x.(qty).uniq? end } x.report("Array.new(#{qty}) == uniq.length") { using Refinements::BooleanUniqWithEqualLength bench_reps.times do array_of_x.(qty).uniq? end } x.report("Array.new(#{qty}) == uniq.sort") { using Refinements::BooleanUniqWithEqualSort bench_reps.times do array_of_x.(qty).uniq? end } x.report("Array.new(#{qty}) each index") { using Refinements::BooleanUniqWithEachIndex bench_reps.times do array_of_x.(qty).uniq? end } x.report("Array.new(#{qty}) combination(2)") { using Refinements::BooleanUniqWithCombination bench_reps.times do array_of_x.(qty).uniq? end } x.report("Array.new(#{qty}) == self.uniq") { using Refinements::BooleanUniqWithUniq bench_reps.times do array_of_x.(qty).uniq? end } end end ~~~ -- https://bugs.ruby-lang.org/