How would you do rose memoization with Sorbet?

两盒软妹~` 提交于 2021-01-27 13:33:43

问题


Trying to annotate this code, the rose memoization (@||=) gives me an error Use of undeclared variable @git_sha.

# typed: strict
# frozen_string_literal: true

module Util
  extend T::Sig

  sig { returns(String) }
  def self.git_sha
    @git_sha ||= ENV.fetch(
      'GIT_REV',
      `git rev-parse --verify HEAD 2>&1`
    ).chomp
  end
end

As far as I've found, I should declare the variable's type with T.let but haven't figured out specifically how.


回答1:


Sorbet now has built-in support for this, as of 0.4.4679. Before that, there were other workarounds (see below).

  1. Initialize the instance variable as T.nilable, and replace all direct access of the instance variable elsewhere with the method:
# typed: strict
# frozen_string_literal: true

module Util
  extend T::Sig

  sig { returns(String) }
  def self.git_sha
    @git_sha = T.let(@git_sha, T.nilable(String))
    @git_sha ||= ENV.fetch(
      'GIT_REV',
      `git rev-parse --verify HEAD 2>&1`
    ).chomp
  end
end

→ View on sorbet.run

This is the the preferred solution.

  1. Initialize the instance variable outside of the method, and give it a type annotation:
# typed: strict
# frozen_string_literal: true

module Util
  extend T::Sig

  @git_sha = T.let(nil, T.nilable(String))

  sig { returns(String) }
  def self.git_sha
    @git_sha ||= ENV.fetch(
      'GIT_REV',
      `git rev-parse --verify HEAD 2>&1`
    ).chomp
  end
end

→ View on sorbet.run

Conceptually, there are two phases of execution for this class: when it's initialized, and when it's used. If an instance variable is not given a type annotation when it is initialized in Sorbet, it will be T.untyped everywhere (or an error in # typed: strict). Because if it's not annotated in the initialize, Sorbet can't know which code path might write into this location first. (Even in this case where there is one location, Sorbet doesn't do that sort of global analysis.)

Sorbet only relaxes this when the instance variable is nilable, in which case it can be initialized anywhere, because Sorbet doesn't need to guarantee that it's initialized as non-nil.

  1. Use a different strictness level.

Docs on strictness levels.

If you find it too burdensome to add a type annotation, you can opt out of requiring a type annotation by using # typed: true, where the error requiring type annotations for instance variables is silenced.



来源:https://stackoverflow.com/questions/56693361/how-would-you-do-rose-memoization-with-sorbet

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!