In order to make use of OpenStruct, `require 'ostruct'` first needs to be declared. Our code neglected to make that declaration, and we saw failures when it was deployed. This code, however, passed all of our tests. We discovered it was because our testing framework included rspec-expectations, which has a dependency on diff-lcs[1], and diff-lcs itself declares `require 'ostruct'`[2]. Because of this, ostruct was loaded globally before our code was tested, which silently masked the underlying issue.
This being said, I do understand the sentiment that this feature seems superfluous and may introduce unnecessary complication, especially from a Rubyist's point of view. The underlying mental model of Ruby dependency management is different from many other languages, and it's something to keep in mind when coming from other languages that do have scope for declared dependencies.
[1] https://github.com/rspec/rspec-expectations/blob/v3.13.3/rsp... [2] https://github.com/halostatue/diff-lcs/blob/v1.5.1/lib/diff/...
The first execution of new code is in CI?
Some new features feel almost prescribed from other languages? Like, RBS and Namespaces specifically... they don't really fit the model of Ruby exactly, but they need to be there so Ruby can be presented as "having" type-safety and a-solution-for-monkey-patching. I'm all for taking inspiration from other places, but Ruby wasn't quite built around the same axioms that other programming languages started from.
It was only after working with Go that I realized how much compile-time safety and performance I was missing out on with Ruby.There's no doubt I would use Ruby today again, but I can't imagine going further beyond simple scripts and workflows. I have recently tried building a very small website with Rails, and I was somewhat surprised the framework did not mature all that much, and type safety and IDE support still seem to be iffy. There is so much unwanted magic that I still see with Ruby on Rails in general. I was looking up to Crystal to address some of the issues I described above, but unfortunately it just remained as a less mature language. Elixir was great, but with the experience I have had, I will actually drop heading into the functional programming world. That leaves me with only one choice, which is Golang. I am not a fan of everything it has, but it is fairly easy for my fellow engineers to pick up, and the IDE support has been nothing short of fantastic.
This is really really a big stretch, but I have always been hopeful towards looking for a TypeScript sort of compile-time layer for Ruby. It may probably never happen though, sadly.
Could you elaborate on this? It's a valid resolution, but I consider Elixir to be on the pragmatic side of the functional paradigm, so I'm wondering what pushed you away.
I'd be interested to hear what you find lacking in Crystal, too. For me it would be editor support, last time I tried the LSP I couldn't get it to work.
I've been working with Ruby for 20 years, and I've not needed something like this. This feels like adding a lot of complexity for little practical benefit. The trade-off feels off. I don't think this is worth the additional complexity.
Follow gem naming conventions and this is a non-issue -- both FooBar::Record and BazQux::Record can coexist for foo_bar and baz_qux gems, respectively. If a gem is defining other top-level constants outside of their gem module, then that's considered against convention, i.e. bad practice, and the language should not be modified to allow such a thing.
I'd like to hear of a real use case for namespaces that existing conventions don't already solve.
This is not the Ruby ethos.
And why would you bother doing that when it would be a breaking change?
Similarly, if you want to group modules that don't conflict together under a short module name, nothing stops you from doing:
module MyGroup
include Module1
include Module2
...
end
In other words, wrapping them doesn't remove your ability to use short non-namespaced names.Using `include` of specific functionality into a class that will use it is furthermore an idiomatic way of avoiding that extra typing without polluting the global namespace
For that matter, you can often achieve close to what you're arguing for as well without actually making any changes to Ruby:
def wrap_load(path) = class_eval(File.read(path), path)
module Test
# some_file.rb will act as-if defined within Test
wrap_load("./some_file.rb")
end
You can do better than that, to get closer to emulate `require` rather than `load`, and handle dependencies.Overall, I think the fact you can do these things suggests you could probably write a good enough plug-in `require` monkeypatch suitable for the rare cases where `include` from within a class or module without needing a language extension.
>First, I'm not convinced by the motivations:
>
>Avoiding name conflicts between libraries: Applications can require two different libraries safely which use the same module name.
>
>Is this a problem that happens on a regular basis? I believe Ruby has a pretty well established convention for libraries to expose a single module with a name that correspond to their gem name.
I really don't think we want to make it easier for newbies to alter gem naming conventions and run multiple versions of a gem within the same project, this sounds like a genuine nightmare to me. I've found from jumping in to fix broken and crippled rails projects for startups that the fuckup surface area is already high enough.
But I don't personally think Shopify would benefit from this specific implementation of namespaces (a couple colleagues do). I'm personally not even sure Namespace is a proper term to describe that feature. It's more some sort of lightweight sandboxing to me.
Also:
> They have so many expert Ruby devs
If anything, the average Ruby expertise at Shopify is likely noticeably lower than in most Ruby/Rails shop.
I personally would love to have this feature!
I'm updating my opinion from "mixed feelings" to "against" on this.
This namespaces feature allows you to manipulate existing globals, but keep it isolated in your own namespace. That seems pretty good to me :) Because it remains isolated, you can also use these features more aggressively.
Over the past two years, I have come to understand that this contributes to the nightmare that is the Nodejs ecosystem (and the browser JS exosystem in general), at least when it comes to writing reliable software.
Maybe after a decade or two I wouldn't care, but as someone who has only used Ruby casually I would steer clear of it for anything serious, largely due to the lack of namespaces.
Even though this is from the YJIT folks, they include the non-jit improvements as a comparison.