My colleagues wrote a library that does something like this. You may want to check it out: https://github.com/thoughtbot/wrapped
Yeah the runtime thing is a disadvantage over type systems for sure. It might be possible with a NillablObject to do some kind of sanity checks at Rails initialization time. Also some other safety nets could help for example use of a ViewModel object to dictate some constraints on Views (type constraints and others).
I like Lucky’s table definition in the model class. A similar construct in AR might be useful in implementing some sanity checks. I often wish there was a way to get a table definition into AR while keeping the goodness of Migrations.
With promises and things like array.map being widely accepted in e.g. JS community, I'd hazard to say that mainstream industrial programming finally starts to embrace the use of monads. It would be great to embrace the most badly missing of them all, Option / Maybe, instead of the "billion dollar mistake" of null. ("Nullable" is a half-step in the right direction.)
It is the "happy path", represented compactly but without a way to forget and step on a nil.
obj&.is&.nil? can replace the use of try obj.try(:is).try(:nil?)
obj = nil
obj&.gsub("f","g") # => nil
obj = "food"
obj&.gsub("f","g") # => "good"
Unfortunately this is not likely second nature and will continue to bite us, especially where our expectations about AR models are not well thought out. A wrapping class for nillables might force safe access of AR attributes.
I like the String? sugar and believe there is probably some opportunity in Rails to address it. For example make a new NillableObject class that wraps the real object or delegates method_missing.
The idea would be to throw a warning, raise an error, etc. when accessing a nillable attribute. This could get obviously more robust than the below example, hook into read_attribute, leverage validations, log a warning instead of raise a runtime error, etc... but hopefully the point is made.