[#100689] [Ruby master Feature#17303] Make webrick to bundled gems or remove from stdlib — hsbt@...

Issue #17303 has been reported by hsbt (Hiroshi SHIBATA).

11 messages 2020/11/02

[#100715] [Ruby master Bug#17306] TestGCCompact#test_ast_compacts test failures — v.ondruch@...

Issue #17306 has been reported by vo.x (Vit Ondruch).

11 messages 2020/11/05

[#100720] [Ruby master Feature#17307] A way to mark C extensions as thread-safe, Ractor-safe, or unsafe — eregontp@...

Issue #17307 has been reported by Eregon (Benoit Daloze).

22 messages 2020/11/05

[#100744] [Ruby master Bug#17310] Closed ractors should die — marcandre-ruby-core@...

Issue #17310 has been reported by marcandre (Marc-Andre Lafortune).

12 messages 2020/11/08

[#100753] [Ruby master Feature#17312] New methods in Enumerable and Enumerator::Lazy: flatten, product, compact — zverok.offline@...

Issue #17312 has been reported by zverok (Victor Shepelev).

11 messages 2020/11/09

[#100763] [Ruby master Feature#17314] Provide a way to declare visibility of attributes defined by attr* methods in a single expression — radek.bulat@...

SXNzdWUgIzE3MzE0IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHJhZGFyZWsgKFJhZG9zxYJhdyBCdcWC

17 messages 2020/11/10

[#100777] [Ruby master Feature#17316] On memoization — sawadatsuyoshi@...

Issue #17316 has been reported by sawa (Tsuyoshi Sawada).

18 messages 2020/11/11

[#100788] [Ruby master Misc#17319] Rename Random::urandom to os_random and document random data sources — zofrex@...

Issue #17319 has been reported by zofrex (James Sanderson).

11 messages 2020/11/11

[#100807] [Ruby master Feature#17322] Deprecate `Random::DEFAULT` and introduce `Random.default()` method to provide Ractor-supported default random generator — ko1@...

Issue #17322 has been reported by ko1 (Koichi Sasada).

14 messages 2020/11/12

[#100816] [Ruby master Feature#17323] Ractor::LVar to provide ractor-local storage — ko1@...

Issue #17323 has been reported by ko1 (Koichi Sasada).

19 messages 2020/11/12

[#100849] [Ruby master Feature#17325] Adds Fiber#cancel, which forces a Fiber to break/return — nicholas.evans@...

Issue #17325 has been reported by nevans (Nicholas Evans).

17 messages 2020/11/14

[#100852] [Ruby master Feature#17326] Add Kernel#must! to the standard library — zimmerman.jake@...

SXNzdWUgIzE3MzI2IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IGpleiAoSmFrZSBaaW1tZXJtYW4pLg0K

24 messages 2020/11/14

[#100858] [Ruby master Feature#17327] The Queue constructor should take an initial set of items — chris@...

Issue #17327 has been reported by chrisseaton (Chris Seaton).

10 messages 2020/11/15

[#100897] [Ruby master Feature#17330] Object#non — zverok.offline@...

Issue #17330 has been reported by zverok (Victor Shepelev).

21 messages 2020/11/17

[#100925] [Ruby master Feature#17331] Let Fiber#raise work with transferring fibers — nicholas.evans@...

Issue #17331 has been reported by nevans (Nicholas Evans).

12 messages 2020/11/18

[#100930] [Ruby master Feature#17333] Enumerable#many? — masafumi.o1988@...

Issue #17333 has been reported by okuramasafumi (Masafumi OKURA).

10 messages 2020/11/18

[#100971] [Ruby master Bug#17337] Don't embed Ruby build time configuration into Ruby — v.ondruch@...

Issue #17337 has been reported by vo.x (Vit Ondruch).

16 messages 2020/11/20

[#100999] [Ruby master Feature#17339] Semantic grouping on BigDecimal#to_s — co.chuma@...

Issue #17339 has been reported by chumaltd (Takahiro Chuma).

9 messages 2020/11/21

[#101071] [Ruby master Feature#17342] Hash#fetch_set — hunter_spawn@...

Issue #17342 has been reported by MaxLap (Maxime Lapointe).

26 messages 2020/11/25

[#101093] [Ruby master Misc#17346] DevelopersMeeting20201210Japan — mame@...

Issue #17346 has been reported by mame (Yusuke Endoh).

17 messages 2020/11/26

[#101141] [Ruby master Bug#17354] Module#const_source_location is misleading for constants awaiting autoload — tom@...

SXNzdWUgIzE3MzU0IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHRvbXN0dWFydCAoVG9tIFN0dWFydCku

21 messages 2020/11/29

[#101143] [Ruby master Feature#17355] Or-patterns (pattern matching like Foo(x) | Bar(x)) — fg@...

Issue #17355 has been reported by decuplet (Nikita Shilnikov).

8 messages 2020/11/29

[#101153] [Ruby master Feature#17356] Alignment of memory allocated through Fiddle struct's malloc — andrea.ribuoli@...

Issue #17356 has been reported by AndreaRibuoli (Andrea Ribuoli).

8 messages 2020/11/30

[ruby-core:100853] Re: [Ruby master Feature#17326] Add Kernel#must! to the standard library

From: Austin Ziegler <halostatue@...>
Date: 2020-11-15 05:19:44 UTC
List: ruby-core #100853
```ruby
task.
  must!.
  mailing_params.
  must!.
  fetch('template_context')
```

I think that this is unreadable and I would never use it in any of my
code=E2=80=94and would reject any PR that contains it in any project I main=
tain. It
reduces the readability of the code to the detriment of debugging bad
runtime behaviour, as it exchanges a `NoMethodError` for a `TypeError`.

Within the small range of methods that `nil` responds to, the type checkers
should be able to analyze that

```ruby
task.mailing_params.fetch('template_context')
```

implies that both `task` and the return from `mailing_params` must not be
`nil` because there is no safe navigation specified.

If something must be done (which to my mind is questionable), it should
probably be done with syntax, because only then can you get something
meaningfully better at run time than either NoMethodError mailing_params on
nil or TypeError nil must! (which is arguably worse at runtime).

I admit that I=E2=80=99m biased against the type checkers as they exist. I=
=E2=80=99ve tried
using both Sorbet and RBS with a gem that I maintain, and I found both of
them completely unusable for this 16 year old gem. I got further with
Sorbet, but an issue that I opened=E2=80=A1 was closed with unhelpful sugge=
stions
(`T.unsafe` is not an answer; I would need that in about 90% of the code,
at which point Sorbet becomes a complete waste of time because the
resulting code is completely unreadable).

I=E2=80=99m not at all willing to give up readability to help programs of
questionable utility do their jobs. IMNSHO, type annotation should be fully
*externally* opt-in for Ruby programs, with all of the readability warts
that implies for those people who choose to use type checkers like Sorbet.
#must! is a type annotation wart that I don=E2=80=99t think belongs in the =
standard
library.

=E2=80=A1 https://github.com/sorbet/sorbet/issues/3252

-a

On Sat, Nov 14, 2020 at 6:15 PM <zimmerman.jake@gmail.com> wrote:

> Issue #17326 has been reported by jez (Jake Zimmerman).
>
> ----------------------------------------
> Feature #17326: Add Kernel#must! to the standard library
> https://bugs.ruby-lang.org/issues/17326
>
> * Author: jez (Jake Zimmerman)
> * Status: Open
> * Priority: Normal
> ----------------------------------------
> # Abstract
>
> We should add a method `Kernel#must!` (name TBD) which raises if `self` i=
s
> `nil` and returns `self` otherwise.
>
>
> # Background
>
> Ruby 3 introduces type annotations for the standard library.
> Type checkers consume these annotations, and report errors for type
> mismatches.
> One of the most common and most valuable type errors is whether `nil` is
> allowed as an argument or return value.
> Sorbet's type system tracks this, and RBS files have syntax for annotatin=
g
> whether `nil` is allowed or not.
>
> Since Sorbet checks proper usage of `nil`, it requires code that looks
> like this:
>
> ```ruby
> if thing.nil?
>   raise "The thing was nil"
> end
>
> thing.do_something
> ```
>
> This is good because it forces the programmer to acknowledge that the
> thing might be `nil`, and declare
> that they'd rather raise an exception in that case than handle the `nil`
> (of course, there are many other
> times where `nil` is both possible and valid, which is why Sorbet forces
> at least considering in all cases).
>
> It is annoying and repetitive to have to write these `if .nil?` checks
> everywhere to ignore the type error,
> so Sorbet provides it as a library function, called `T.must`:
>
> ```ruby
> T.must(thing).do_something
> ```
>
> Sorbet knows that the call to `T.must` raises if `thing` is `nil`.
> To make this very concrete, here's a Sorbet playground where you can see
> this in action:
>
> [=E2=86=92 View on sorbet.run](
> https://sorbet.run/#%23%20typed%3A%20true%0Aextend%20T%3A%3ASig%0A%0Aclas=
s%20Thing%0A%20%20def%20do_something%3B%20end%0Aend%0A%0Asig%20%7Bparams(th=
ing%3A%20T.nilable(Thing)).void%7D%0Adef%20example1(thing)%0A%20%20%23%20er=
ror%2C%20might%20be%20nil%3A%0A%20%20thing.do_something%0Aend%0A%0Asig%20%7=
Bparams(thing%3A%20T.nilable(Thing)).void%7D%0Adef%20example2(thing)%0A%20%=
20if%20thing.nil%3F%0A%20%20%20%20raise%20%22The%20thing%20was%20nil%22%0A%=
20%20end%0A%0A%20%20%23%20no%20error%2C%20because%20it's%20after%20the%20%6=
0if%20.nil%3F%60%20check%3A%0A%20%20thing.do_something%0Aend%0A%0Asig%20%7B=
params(thing%3A%20T.nilable(Thing)).void%7D%0Adef%20example3(thing)%0A%20%2=
0%23%20no%20error%2C%20because%20it's%20after%20the%20%60if%20.nil%3F%60%20=
check%3A%0A%20%20T.must(thing).do_something%0Aend
> )
>
> You can read more about `T.must` in the [Sorbet documentation](
> https://sorbet.org/docs/type-assertions#tmust).
>
>
> # Problem
>
> While `T.must` works, it is not ideal for a couple reasons:
>
> 1.  It is not a method, so you can't `map` it over a list using
> `Symbol#to_proc`. Instead, you have to expand the block:
>
>     ```ruby
>     array_of_integers =3D array_of_nilable_integers.map {|x| T.must(x) }
>     ```
>
> 2.  It leads to a weird outward spiral of flow control, which disrupts
> method chains:
>
>     ```ruby
>     # =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
=80=E2=94=80=E2=94=80=E2=94=90
>     # =E2=94=82      =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
=90     =E2=94=82
>     # =E2=96=BC      =E2=96=BC    =E2=94=82     =E2=94=82
>     T.must(T.must(task).mailing_params).fetch('template_context')
>     # =E2=94=82      =E2=94=82          =E2=96=B2               =E2=96=B2
>     # =E2=94=82      =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=98               =E2=
=94=82
>     # =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=
=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
=94=80=E2=94=80=E2=94=98
>     ```
>
>     compare that control flow with this:
>
>     ```ruby
>     # =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=90=E2=94=8C=E2=
=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=90=E2=94=8C=E2=94=80=E2=94=80=E2=94=
=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=
=E2=94=80=E2=94=80=E2=94=90=E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=
=94=90
>     # =E2=94=82    =E2=96=BC=E2=94=82    =E2=96=BC=E2=94=82             =
=E2=96=BC=E2=94=82    =E2=96=BC
>       task.must!.mailing_params.must!.fetch('template_context')
>     ```
>
> 3.  It is in a Sorbet-specific gem. We do not intend for Sorbet to be the
> only type checker.
>     It would be nice to have such a method in the Ruby standard library s=
o
> that it can be shared by all type checkers.
>
> 4.  This method can make Ruby codebases that **don't** use type checkers
> more robust!
>     `Kernel#must!` could be an easy way to assert invariants early.
>     Failing early makes it more likely that a test will fail, rather than
> getting `TypeError`'s and `NoMethodError`'s in production.
>     This makes all Ruby code better, not just the Ruby code using types.
>
>
> # Proposal
>
> We should extend the Ruby standard library with something like this::
>
> ```ruby
> module Kernel
>   def must!; self; end
> end
>
> class NilClass
>   def must!
>     raise TypeError.new("nil.must!")
>   end
> end
> ```
>
> These methods would get type annotations that look like this:
> (using Sorbet's RBI syntax, because I don't know RBS well yet)
>
> ```ruby
> module Kernel
>   sig {returns(T.self_type)}
>   def must!; end
> end
>
> class NilClass
>   sig {returns(T.noreturn)}
>   def must!; end
> end
> ```
>
> What these annotations say:
>
> - In `Kernel#must!`, the return value is `T.self_type`, or "whatever the
> type of the receiver was."
>   That means that `0.must!` will have type `Integer`, `"".must!` will hav=
e
> type `String`, etc.
>
> - In `NilClass#must!`, there is an override of `Kernel#must!` with return
> type `T.noreturn`.
>   This is a fancy type that says "this code either infinitely loops or
> raises an exception."
>   This is the name for Sorbet's [bottom type](
> https://en.wikipedia.org/wiki/Bottom_type), if you
>   are familiar with that terminology.
>
> Here is a Sorbet example where you can see how these annotations behave:
>
> [=E2=86=92 View on sorbet.run](
> https://sorbet.run/#%23%20typed%3A%20true%0A%0Amodule%20Kernel%0A%20%20T%=
3A%3ASig%3A%3AWithoutRuntime.sig%20%7Breturns(T.self_type)%7D%0A%20%20def%2=
0must!%3B%20self%3B%20end%0Aend%0A%0Aclass%20NilClass%0A%20%20T%3A%3ASig%3A=
%3AWithoutRuntime.sig%20%7Breturns(T.noreturn)%7D%0A%20%20def%20must!%0A%20=
%20%20%20raise%20TypeError.new(%22nil.must!%22)%0A%20%20end%0Aend%0A%0Axs%2=
0%3D%20T%3A%3AArray%5BInteger%5D.new(%5B0%5D)%0AT.reveal_type(xs.first)%20%=
20%20%20%20%20%20%23%20T.nilable(Integer)%0AT.reveal_type(xs.first.must!)%2=
0%23%20Integer%0A%0Ays%20%3D%20T%3A%3AArray%5BT.nilable(Integer)%5D.new(%5B=
0%2C%20nil%2C%201%2C%20nil%2C%202%5D)%0AT.reveal_type(ys)%20%20%20%20%20%20=
%20%20%20%20%20%20%20%20%23%20T%3A%3AArray%5BT.nilable(Integer)%5D%0AT.reve=
al_type(ys.map(%26%3Amust!))%20%23%20T%3A%3AArray%5BInteger%5D
> )
>
> # Alternatives considered
>
> There was some discussion of this feature at the Feb 2020 Ruby Types
> discussion:
>
> Summarizing:
>
> - Sorbet team frequently recommends people to use `xs.fetch(0)` instead o=
f
> `T.must(xs[0])`
>   on `Array`'s and `Hash`'s because it chains and reads better.
>   `.fetch` not available on other classes.
>
> - It's intentional that `T.must` requires as many characters as it does.
>   Making it slightly annoying to type encourages developers to refactor
> their code so that `nil` never occurs.
>
> - There was a proposal to introduce new syntax like `thing.!!`. This is
> currently a syntax error.
>
>   **Rebuttal**: There is burden to introducing new syntax. Tools like
> Rubocop, Sorbet, and syntax highlighting
>   plugins have to be updated. Also: it is hard to search for on Google (a=
s
> a new Ruby developer). Also: it
>   is very short=E2=80=94having something slightly shorter makes people th=
ink about
> whether they want to type it out
>   instead of changing the code so that `nil` can't occur.
>
> Another alternative would be to dismiss this as "not useful / common
> enough". I don't think that's true.
> Here are some statistics from Stripe's Ruby monolith (~10 million lines o=
f
> code):
>
> | methood | percentage of files mentioning method | number of occurrences
> of method |
> | --- | --- | --- |
> | `.nil?` | 16.69% | 31340 |
> | `T.must` | 23.89% | 74742 |
>
> From this, we see that
>
> - `T.must` is in 1.43x more files than `.nil?`
> - `T.must` occurs 2.38x more often than `.nil?`
>
>
> # Naming
>
> I prefer `must!` because it is what the method in Sorbet is already calle=
d.
>
> I am open to naming suggestions. Please provide reasoning.
>
>
> # Discussion
>
> In the above example, I used `T.must` twice. An alternative way to have
> written that would have been using save navigation:
>
> ```ruby
> T.must(task&.mailing_params).fetch('template_context')
> ```
>
> This works as well. The proposed `.must!` method works just as well when
> chaining methods with safe navigation:
>
> ```ruby
> task&.mailing_params.must!.fetch('template_context')
> ```
>
> However, there is still merit in using `T.must` (or `.must!`) twice=E2=80=
=94it
> calls out that the programmer
> intended neither location to be `nil`. In fact, if this method had been
> chained across multiple lines,
> the backtrace would include line numbers saying specifically **which**
> `.must!` failed:
>
>
> ```ruby
> task.must!
>   .mailing_params.must!
>   .fetch('template_context')
> ```
>
>
>
>
> --
> https://bugs.ruby-lang.org/
>
> Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=3Dunsubscrib=
e>
> <http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>
>


--=20
Austin Ziegler =E2=80=A2 halostatue@gmail.com =E2=80=A2 austin@halostatue.c=
a
http://www.halostatue.ca/ =E2=80=A2 http://twitter.com/halostatue

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread