1. 5

    I’m working on a Ruby talk called “Metaprogramming with super powers” that I’m giving at the Indianapolis Ruby Brigade meetup on Valentine’s Day. Sadly it was rejected from RailsConf, so I’m 0/4 on my conference talk submissions - just gonna keep working the meetup circuit.

    Also working on some finishing touches on an Instrumentation gem based loosely on my blog post on instrumenting Ruby methods. I released 1.0 last Friday, but there’s still some improvements I want to make. It’s not currently open source, but may be suitable to release at some point.

    1. 2

      It has been bothering me that I used the word ‘fake’ in the title rather than something more-accurate such as ‘misleading’. It is possible to achieve records using emulation, and can still be an accomplishment IF there’s no abuse of emulation features that allow “rewinding” or other cheats not possible in the “regular” course of gameplay.

      There’s a huge amount of drama that goes along with these records and Billy Mitchell that I have zero stake in - as mentioned in the submission the aspect I found most-interesting here was the breakdown of MAME vs original.

      1. 1

        I noticed that this library is performance tested, with assert statements that make sure that a given function is executed within X ms.

        Are these kinds of tests helpful? Does it not make a difference what machine the tests are running on? Or if the test runner instance is responsible for running other test suites too and happened to be overloaded at the time these performance tests ran?

        Or is there a way to isolate machine resources so that such tests yield predictable/consistent results?

        1. 1

          I’d say they are useful for preventing performance regression. They are likely fairly consistent, but it is true that there’s potential signal pollution that can occur.

          1. 1

            Exactly. I’ve done this type of assertion before and you wind up having to put such a wide margin of error in it (like order of magnitude with modern, cloud CI boxes) that it doesn’t catch anything but the most egregious of regressions.

            That said, you can still assert relative comparisons (assert my time < “other gem” time) with some confidence.

            1. 2

              Ug I missed that. Well-spotted

            1. 2

              FWIW the author discussed this idea on Twitter with Matz:

              Nick Sutterer (@apotonick): Hi @yukihiro_matz - what do you think about this? https://apotonick.wordpress.com/2018/01/17/dear-ruby-1-what-about-arguments-when-inheriting/ (I’m probably not the first one with this idea?!)

              Yukihiro Matsumoto (@yukihiro_matz): @apotonick How about generating a class to be a superclass?

              class Foo<Bar(args) … end

              where Bar() is a method that returns a class.

              Nick Sutterer (@apotonick): @yukihiro_matz Yes, that’s the current approach in many gems. However, this implies some meta programming and an anonymous class, whereas the extended ::included signature would be consistent and in-line with #initialize, right? Thanks Matz!

              Yukihiro Matsumoto (@yukihiro_matz): @apotonick I am afraid that I don’t share that “consistent and in-line with” feeling.

              Nick Sutterer (@apotonick): @yukihiro_matz 😬 It’s “create an intermediate, anonymous class between A and subclass B” vs. “allow passing explicit arguments and set variables on B after B is inherited, the way you do it when creating object instances”

              Nick Sutterer (@apotonick): @yukihiro_matz Ok, let’s forget the “consistent” argument. What’s better: passing arguments to a method, or having to create a temporary anonymous class to transport those arguments?

              Yukihiro Matsumoto (@yukihiro_matz): @apotonick Yours consumes less memory. That is good. But it may make the language more complex.

              Besides that, considering potential code breakage, I cannot simply say yours is “better”.

              Nick Sutterer (@apotonick): @yukihiro_matz Thanks, agreeing. ✌️My idea introduces a syntactical change, true. Does that make the language more complex? Yes.

              Creating an intermediate class instead: makes the USE of the language more complex.

              Could there be any incompat, though? 🤔🤓🧐

              Yukihiro Matsumoto (@yukihiro_matz): @apotonick Your particular example

              class Memo::Render < Render, engine: Render::JSON … end

              does not conflict with existing syntax (due to the comma after ‘Render’), but I am not positive with a comma here because it reminds me multiple inheritance.

              Nick Sutterer (@apotonick): @yukihiro_matz Many thanks, I will elaborate more on this idea and talk to other gem authors about whether or not it would be cool to have that, etc. So there is no other proposal for this, yet? Haha, maybe I’m crazy 🤪 thanks!

              1. 2

                Here’s the approach Matz is referring to: https://gist.github.com/bkudria/82e3721d4ec2b62a2a3d95050e964d84

              1. 6

                A super rough rule of thumb: use getters if you need to perform logic to determine the property. Use setters if you need to maintain a class invariant. Otherwise use direct access.

                1. 8

                  Always using methods for access is a type of future proofing since you can never be sure when you may need to add logic around access, and so a method is more tolerant of change over time. The interface changes if you switch from property access to method access in Java.

                  I have no strong opinion, though, since I see it as a judgement call.

                  1. 8

                    My question is how often has the working programmer ever had to do that? I don’t remember ever doing this in all my years of software. Not once have I been able to take advantage of the fake insurance policy that getters and setters provide.

                    Well, I have had to do it before. Maybe the author writes more green field stuff than maintaining systems.

                    1. 2

                      In most cases, you’ve got the source code that uses the object. Just change the code.

                      1. 1

                        Less-helpful for writing libraries used by several code bases - also something I have done several times. This is why it’s a judgement call to me. You are in a better place to predict how your code will be used than I am.

                  1. 3

                    I’m feeling like crustaceans don’t care about Ruby any more based on my recent Ruby stories submitted. Hell, even Matz tweeted a link to this post - but very little attention here. What’s with that?

                    1. 5

                      I think that Ruby is generally waning. The smaller regional conferences are disappearing (MountainWest, KRW, Ruby on Ales, Ruby Midwest, Ancient City…), the Google searches are dropping, the StackOverflow tag is dropping, a number of the most prominent Rails/big gem contributors have partially or wholly moved off to other languages. I haven’t made time to play with the RubyGems data, but I expect downloads to be flat or declining and new gems/releases to be declining.

                      My best guess is that it’s because Ruby’s popularity is mostly driven by Rails, and Rails didn’t have a great story integrating the big increase in frontend complexity that started with the wave of libraries like Angular in 2009-2010. A lesser factor is that a lot of the attributes that make Ruby so fun for small scripts and quick for prototypes are anti-features for large, long-lived codebases, so folks are rewriting rather than maintaining. Or maybe it’s just a fad that’s fading; programmers are certainly not immune to marketing.

                      1. 2

                        I think the hype cycle is over for Ruby/Rails. The early adopters who shaped some of the popular projects have moved on because it’s more fun for them to trailblaze in a new community than it is to maintain things in a more-mature community. There’s still a hell of a lot of active rubyists, but maybe they’re no longer present here as much as they used to be.

                        I appreciate your thoughtful response with links and data :) Interpretation is debatable, e.g. I think npm is a cesspool of microlibraries that don’t indicate healthy library development activity.

                        I do wonder if I should continue posting Ruby links given little positive reinforcement that people care about them.

                        1. 5

                          I like that Lobsters has a lot of niche-interest stories. I’m a little sad to see Ruby returning to niche status, but that doesn’t mean these things are off-topic or not worth discussing.

                      2. 3

                        I can think of a couple of reasons:

                        • In general, most language posts don’t get a whole lot of upvotes. You just have a more limited audience in a specific language than in a programming topic.
                        • The article is about a couple of small methods added to Ruby. That’s interesting, I guess, but reading it doesn’t make me a better programmer. I doesn’t give me any sort of insight or inspiration or entertainment beyond “oh, okay.” Compare this, which is about security via Ruby, or this which is about how small differences between languages can slow you down. They’re highly upvoted in part because they’re worth reading even if you’re not a Rubyist.
                        1. 1

                          Thanks for your reasoned response. If I’m being completely honest, this is likely a knee jerk from my own post being overlooked which I’m over-sensitive about since I just barely started writing again.

                      1. 7

                        Wow this really exploded! Just a heads up to anybody creating an account, use joinmastodon.org and find a different instance than mastodon.social, it aint really decentralized if everybody is on the same server!

                        1. 1

                          I didn’t think much about it when I signed up. Is there a good way to migrate to other servers? I did dig up this github issue which AFAICT is unresolved - limitations of the protocol?

                          Maybe I ought to just hop to another server before I’m too invested in my meager presence on mastodon.social

                          1. 3

                            Go in settings and export your follow list, then import into your new account. I think thats all you can do right now, but I still recommend it, as mastodon.social tends to go down everytime there’s a big twitter migration.

                            1. 1

                              Did that and it worked fine.

                              I don’t care about keeping my old toots, though. I consider my social media stuff ephemeral. Auto-deleting is not implemented unfortunately…

                            2. 1

                              kensanata also wrote a backup tool for all your toots etc. here: https://github.com/kensanata/mastodon-backup

                          1. 3

                            @soulcutter@mastodon.social

                            Thanks for posting this - a barrier to adoption for me is discovering people on there to follow.

                            1. 2

                              You may come to the point, where you to have certain elements that are bound to your model but don’t belong either there nor in the controller.

                              I don’t follow why they don’t belong in the model. These are behaviors that change the state of the model - it’s deeply coupled to attributes provided by the model. I am not convinced this is an example of good design, though it does cover the mechanics of how you can use that feature.

                              1. 3

                                Ironic that none of the table examples render properly on my phone…

                                1. 1

                                  What phone/browser?

                                  This does seem fairly cutting-edge since I cannot even find font-variant-numeric in caniuse search - there’s some discussion about it on github.

                                  It’s disappointing to have found this and thought “Cool! This will be useful!” and then discovering it’s poorly-supported.

                                  1. 2

                                    On iPhone, all the table cells are rendered in a vertical list.

                                    Header1
                                    Header2
                                    Header3
                                    Data1
                                    Data2
                                    Data3
                                    
                                1. 3

                                  I am not sold on some of the approaches outlined here - e.g. OpenStruct is a scourge that has no place in 99.9% of Ruby code. Also there’s a lot of ActiveSupport-related advices in here, which is an unnecessary dependency in many cases.

                                  All in all, I don’t think this post shows the best solutions, but it DOES show some solutions that are commonly-encountered.

                                  How do YOU approach configuration?

                                  1. 1

                                    Welp, it looks like nobody is going to jump in and contribute, so let me put forth one good Ruby solution: dry-configurable

                                  1. 3

                                    Silent failure: If you provided an email address that was not currently in the CCs list, the endpoint would return a message stating the email had been removed successfully.

                                    That was listed as an oversight that led to a problem, but that actually sounds like a reasonable security feature to me - you should not be able to find out who is following as issue by trying to remove them.

                                    1. 1

                                      I don’t understand why the claims about the AI not being better than a human because it takes them more games to learn winning strategies than humans take. One of the big advantages of computers is that they can perform that sort of ‘practice’ VERY quickly - far faster than a human is able to do. This is really cool, though, and an achievement in learning from first principles.

                                      1. 1

                                        I had figured Heroku users are in a better position than most as far as this goes.

                                        Meta: You can mark yourself as the author of a submission. Unsure if you just missed that here (no big deal)

                                        1. 1

                                          You can mark yourself as the author of a submission

                                          Sorry, thought I did. Thanks for the reminder.

                                        1. 1

                                          I find this approach really interesting. Personally, From a RoR perspective, I find this approach the easiset to maintain and to read. It keeps the important bits of the logic isolated into its own namespace and keeps the application fairly clutter free.

                                          First set a memoized helper in the application_controller.rb called permitted_params. This will now be accessible in the controllers.

                                          # application_controller.rb
                                          def permitted_params
                                            @permitted_params ||= Params::PermittedParams.new(params, current_user)
                                          end
                                          helper_method :permitted_params
                                          

                                          Within the controllers, I can use permitted_params.user instead of the params.

                                          # users_controller.rb create action
                                          @user = User.create(permitted_params.user)
                                          

                                          I’ll then have a separate folder for all of the strong params logic. Within the folder, I’ll create a new params for each ActiveRecord model.

                                          app/params/params.rb
                                          class Params::PermittedParams < Struct.new(:params, :current_user)
                                            include Params::User
                                          end
                                          

                                          Since our permitted_params helper takes in the params and the current_user, we can use that in our user.rb methods. I’ll access the params and first required the [:user] parameter to exist and then permit from a private method called user_attributes.

                                          This private method will return an array. We can build out the allowed parameters here as well as having access to limit what parameters a user can write to. In this case, I would only allow the admin attribute to be written to by user input if the current user is already an admin.

                                          # app/params/user.rb
                                          module Params
                                            module User
                                              def user
                                                params.require(:user).permit(*user_attributes)
                                              end
                                          
                                              private
                                          
                                              def user_attributes
                                                [].tap do |attributes|
                                                  attributes << :first_name
                                                  attributes << :last_name
                                                  attributes << :admin if current_user.admin?
                                                end.flatten
                                              end
                                            end
                                          end
                                          
                                          1. 1

                                            Params::PermittedParams

                                            So this object ends up being a sort of global registry of params logic per-model? Hmm, I have some thoughts around this, thanks for sharing!

                                            1. 1

                                              I’ve used it in small apps as well as larger ones and it’s kept the code fairly clean. Since it’s also leveraging memoization, having it called multiple times in a controller/view/presenter keeps the footprint the same. I would probably have a concern if my app had thousands of AR models, but so far it’s been pretty efficient.

                                          1. 1

                                            Not much here yet - but I am looking forward to this. Probably jumped the gun on submitting it (apologies)

                                            1. 6

                                              Notably missing from the article (probably, because it is called “everything you should know about Ruby splats”): Ruby being Ruby, splat behaviour can be overloaded…

                                              class MyClass < Struct.new(:a, :b, :c)
                                                def to_splat
                                                  [a, b, c]
                                                end
                                              end
                                              
                                              def insplat(*splatted)
                                                puts splatted.inspect
                                              end
                                              
                                              m = MyClass.new(1, 2, 3)
                                              insplat(*m)
                                              # => [1, 2, 3]
                                              
                                              1. 5

                                                What version of Ruby is that? I don’t think your example is valid - I think what’s going on there is that Struct implements #to_a

                                                class Bar
                                                  def initialize(x, y)
                                                    @x, @y = x, y
                                                  end
                                                
                                                  def to_splat
                                                    [@y, @x]
                                                  end
                                                end
                                                def things(one, two); puts "#{one} #{two}" end
                                                
                                                things(*Bar.new(2, 1)) # => ArgumentError: wrong number of arguments (given 1, expected 2)
                                                
                                                class Bar; def to_a; to_splat end end
                                                things(*Bar.new(2, 1)) # => nil
                                                1 2
                                                
                                                1. 5

                                                  Hah, how embarassing. It seems to have gone. It’s documented in “The Ruby Programming Language” (Flanagan, Matsumoto).

                                                  Here’s the commit introducing it, I can’t find the one that removes it…

                                                  https://github.com/ruby/ruby/commit/9317700a5dc77053b84180456fa0ae10a3d33218

                                                  And the docs where I got it from:

                                                  http://www.eigenclass.org/hiki/ChangesinRuby1.9#l13

                                                  Should have checked if the method is called…

                                                  Thanks for the correction!

                                                  1. 4

                                                    That’s a neat piece of Ruby history/trivia! Thanks for digging up the references.

                                                    I should mention that my initial intuition was that it was using #to_ary so I get a small sense of validation knowing that it used to be that! Very curious that splatting has changed over time like that without many people noticing.

                                                    1. 3

                                                      There’s this time from Ruby 1.9.0 to 1.9.3 where Ruby 1.9 was kinda there, but more in a soul-searching phase. You could port things to it and it was mostly stable, but there was also not a lot of adoption and people wouldn’t be pressured to switch. It was probably my most intense Ruby-learning time, as I was running nightly builds all the time to see what worked already and ported old stuff over.

                                                      I assume that it was introduced during that time and subsequently removed.

                                                  2. 2

                                                    To clarify: splat calls the explicit array conversion method (to_a) if it’s defined and falls back to the implicit conversion (to_ary) if it’s not.

                                                1. 1

                                                  Ok, but does this matter? Even a 50% speedup won’t matter much unless a program spends a significant portion of its time doing hash calculations on arrays, which seems unlikely (at least, unusual). I’m not too surprised the Java devs haven’t been too bothered about this.

                                                  1. 3

                                                    Performance is death by a thousand cuts. Good performance, performance so good you don’t have to bother optimizing your app, is often the result of thousands of people who sweat the details and agonize over nanoseconds and stalls caused by data dependence. People like the author.

                                                    1. 2

                                                      I would say that it’s not a problem - until it is. It’s good to have this kind of information available, but even the tone of the article is that one should avoid prematurely optimizing, since changes in the JVM are likely to render those optimizations moot at some point.

                                                      1. 2

                                                        I didn’t take that away. There are a few tidbits that are fundamental to Hotspot and probably aren’t going to change anytime soon. One is that more small methods is better than large methods as the JIT works best on smaller blocks of code and does aggressive inlining so hot methods have no call overhead anyway. Also final variables help with with things like constant propagation. Things related to GC performance are also worth over-fitting for as it takes like a decade between new GCs to get into the JDK.

                                                        If anything, I took away from the article that there’s enough time between JDK releases that micro-optimizations you implement now have a shelf-life of years, not months.

                                                    1. 9

                                                      a huge amount of information that previously would’ve been in emails ends up in Slack, and only in Slack

                                                      I prefer this, because slack history doesn’t get misplaced like email does, and when a new person joins they have access to the history. Orgs could leverage google groups (or some mailing list archives) to get this same nicety, but I’ve never seen that happen in-practice.

                                                      I trawl Slack history on a weekly basis, while I quite regularly see emails fall through the cracks and become unreachable. Maybe I suck at email? I don’t know, but it’s a problem I have, and have seen others have.

                                                      As a remote worker, Slack (or something like it) is a bit of a lifeline for me. I do get plenty of alone time (hey, I’ve got an office with a door at home!), but an email feedback loop for everything would slow me and other people down incredibly, while also losing a sense of community.

                                                      Some of the hate seems to be from misuse. Can’t be safely ignored? Come on, just don’t read the entire backlog - mark as read and move on after your vacation. Sounds like a bad company culture or a control-freak personality negatively affecting this person. If there’s important stuff that happened while you were on vacation, your manager or colleagues should be able to catch you up or point out things to you.

                                                      Can it be a distraction? Sure. I think the benefits outweigh the costs. The days of distraction-free workplaces are over. Maybe I’m too young, but I’m honestly not sure if they ever really existed at this point - and I’ve been in the industry for 15 years. You need to find ways to carve out distraction-free time - it’s really not that much harder than blocking it off on your calendar I’ve found (and yes, stopping notifications. It can be done!)

                                                      Now there’s other points I can get onboard with - the lock-in, and increasingly silly level of integrations are a bother.

                                                      I really don’t like it for public communities because there’s no good moderation, usually lacking the history that I find valuable (most communities are on the ‘free’ 10k message backlog version it seems), and that’s where the proprietary thing really stinks because you’re at the whim of Slack’s goodwill. Several public communities have outgrown Slack’s free tier, and have had to expend wasteful effort to shift to other platforms (and there goes your community).

                                                      1. 3

                                                        I prefer this, because slack history doesn’t get misplaced like email does, and when a new person joins they have access to the history. Orgs could leverage google groups (or some mailing list archives) to get this same nicety, but I’ve never seen that happen in-practice.

                                                        I work with gecko at Khan Academy and we actually do use google groups extensively. I can’t imagine a new person getting much value from old Slack history.

                                                        Ideally, stuff that a new person needs would exist in some place other than email or Slack. A docs repository, an issue tracking system, etc.

                                                        1. 1

                                                          I neglected to mention that I often pin important stuff in slack. If it’s something that needs to stick around a long time, I would agree that Slack should not be the sole repository for that information.