Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyでのタイプチェック—YoSelfを破壊する前にYoSelfをチェックしてください

この投稿を楽しいちょっとした推測ゲームから始めましょう。RubyアプリケーションでAppSignalによって追跡される最も一般的なエラーは何だと思いますか?

多くの人がこの質問にNoMethodErrorで答えたと考えるのが妥当です。 、オブジェクトで存在しないメソッドを呼び出すことによって発生する例外。場合によっては、これはメソッド名のタイプミスが原因である可能性がありますが、多くの場合、間違ったタイプのオブジェクトでメソッドを呼び出した結果であり、予期しないnilであることがよくあります。 。このようなエラーの頻度を減らすために、Ruby開発者としてできることはありますか?

救助の種類は?

テキストエディタまたはプログラミング言語の選択を除いて、型システムの議論よりも早く白熱した議論に巻き込まれるトピックはほとんどありません。ここで詳細を説明する時間はありませんが、ChrisSmithの投稿「型システムについて議論する前に知っておくべきこと」はその点で優れています。

広義には、型システムは静的と動的の2つの主要なカテゴリに分類できます。前者は(コンパイラまたは別のツールを介して)事前に実行されますが、動的型チェックは実行時に発生し、実際の型が開発者の期待に合わない場合は例外が発生する可能性があります。

両方の哲学の支持者は強い意見を持っていますが、残念ながら、静的型付けには大量の型注釈は必要ありません。多くの最新のコンパイラーは、「型推論」と呼ばれるプロセスで、独自に型を理解できます。一方、動的に型付けされた言語は、静的に型付けされた言語よりも大幅に高い欠陥率を示すようには見えません。

ダックタイピング

Ruby自体は動的に型チェックされる言語であり、「ダックタイピング」アプローチに従います。

それがアヒルのように歩き、アヒルのように震えるなら、それはアヒルでなければなりません。

これが意味するのは、Ruby開発者は通常、オブジェクトのタイプについてはあまり気にしないが、特定の「メッセージ」(またはメソッド)に応答するかどうかについては気にしないということです。

では、なぜRubyで静的型付けを気にするのでしょうか?コードを魔法のようにバグのないものにするのは確かに万能薬ではありませんが、特定の利点があります:

  • 正しさ:静的型付けは特定のクラスを防ぐのに適しています 前述のNoMethodErrorのようなバグの 。
  • ツール:多くの場合、開発中に静的タイプ情報を利用できると、ツールオプションが向上します(IDEでのリファクタリングサポートなど)
  • ドキュメンテーション:静的に型付けされた多くの言語には、優れたドキュメンテーションツールが組み込まれています。 Haskell's Hoogleは、型シグネチャによって関数を検索できる検索エンジンを提供することにより、これを非常に効果的に使用しています。
  • パフォーマンス:コンパイラーが利用できる情報が多いほど、適用できる可能性のあるパフォーマンスの最適化も多くなります。

このリストは網羅的なものではなく、これらの点のほとんどの反例を見つけることができますが、確かにそれらには真実の核心があります。

漸進的型付けチェック

近年、一般に「漸進的型チェック」と呼ばれるアプローチが、JSのTypeScriptからPHPのHack、Pythonのmypyまで、さまざまな動的に型チェックされる言語に浸透しています。これらのアプローチに共通しているのは、オールオアナッシングアプローチを必要としないということですが、代わりに、開発者が適切と思われる変数と式に型情報を徐々に追加できるようにします。これは、システムの最も重要な部分を静的にチェックしながら、残りの部分を型指定せずに実行時にチェックできる既存の大規模なコードベースで特に役立ちます。この記事の残りの部分で説明するRubyのすべての型チェックソリューションは、同じアプローチに従います。

オプション

Ruby開発者が静的型チェックを開発ワークフローに追加する理由を確認した後、現在人気のあるオプションのいくつかを検討します。ただし、静的型チェックをRubyに追加するという考え方は新しいものではないことに注意することが重要です。メリーランド大学の研究者は、早くも2009年にDiamondback Ruby(Druby)という名前のRuby拡張機能に取り組み、Tufts University ProgrammingLanguageGroupは2013年にRubyTypeCheckerという論文をリリースし、最終的にRDLプロジェクトにつながりました。ライブラリとしてのチェックおよび契約による設計機能。

シャーベット

Stripeによって開発されたSorbetは、現在最も話題になっているRubyの型チェックソリューションです。特に、Shopify、GitLab、Kickstarter、Coinbaseなどの大企業がクローズドベータフェーズで早期に採用されたためです。もともとは昨年のRubyKaigiで発表され、今年の6月20日に最初の公開が行われました。シャーベットは最新のC++で記述されており、Matzの好み(引用:「タイプアノテーションが嫌い」)にもかかわらず、タイプアノテーションに基づくアプローチを選択しました。 Sorbetの特に興味深い点の1つは、静的型システムではRubyの非常に動的な性質とメタプログラミング機能が難しいため、静的型と動的型のチェックの組み合わせを選択することです。

# typed: true
class Test
  extend T::Sig
 
  sig {params(x: Integer).returns(String)}
  def to_s(x)
    x.to_s
  end
end

タイプチェックを有効にするには、最初に# typed: trueを追加する必要があります 魔法のコメントとT::Sigでクラスを拡張します モジュール。実際の型アノテーションはsigで指定されます 方法:

sig {params(x: Integer).returns(String)}

これは、このメソッドがxという名前の単一の引数を取ることを指定します タイプはInteger Stringを返します 。間違った引数タイプでこのメソッドを呼び出そうとすると、エラーが発生します:

Test.new.to_s("42")
# Expected Integer but found String("42") for argument x

これらの基本的なチェックとは別に、Sorbetにはさらに多くのトリックがあります。たとえば、恐ろしいNoMethodErrorから私たちを救うことができます nil

users = T::Array[User].new
user = users.first
user.username
 
# Method username does not exist on NilClass component of T.nilable(User)

上記のスニペットは、Userの空の配列を定義しています オブジェクトと最初の要素にアクセスしようとすると(nilが返されます) )Sorbetは、usernameという名前のメソッドがないことを正しく警告します。 NilClassで利用できます 。ただし、特定の値がnilになることはないと確信している場合 、T.mustを使用できます シャーベットにこれを知らせるには:

users = T::Array[User].new
user = T.must(users.first)
user.username

上記のコードはタイプチェックになりますが、ランタイム例外が発生する可能性があるため、この機能は注意して使用してください。

Sorbetができることは他にもたくさんあります。デッドコードの検出、型の固定(基本的に、変数を特定の型にコミットします。たとえば、文字列が割り当てられると、整数を割り当てることはできません)、または機能です。インターフェイスを定義します。

さらに、Sorbetは「RubyInterface」ファイル(rbi)でも機能します。 )sorbet/に保存します 現在の作業ディレクトリ内のフォルダ。これにより、プロジェクトが使用するすべてのgemのインターフェース定義を生成できるようになり、さらに多くの型エラーを見つけるのに役立ちます。

Sorbetには、1つの記事でカバーできる以上のものがあります(たとえば、さまざまな厳密性レベルやメタプログラミングプラグイン)が、そのドキュメントはすでにかなり優れており、PRに公開されています。

急勾配

シャーベットの最も広く知られている代替品は、松本宗太郎による急勾配です。注釈を使用せず、それ自体で型推論を行いません。代わりに、.rbiに完全に依存しています sig内のファイル ディレクトリ。

次の単純なRubyクラスから始めましょう:

class User
  attr_reader :first_name, :last_name, :address
 
  def initialize(first_name, last_name, address)
    @first_name = first_name
    @last_name = last_name
    @address = address
  end
 
  def full_name
    "#{first_name} #{last_name}"
  end
end

これで、最初のuser.rbiをスキャフォールディングできます 次のコマンドでファイルを作成します:

$ steep scaffold user.rb > sig/user.rbi

これにより、開始点として意図された次のファイルが作成されます(すべてのタイプがanyとして指定されているという事実によって示されています) 、安全性はありません):

class User
  @first_name: any
  @last_name: any
  @address: any
  def initialize: (any, any, any) -> any
  def full_name: () -> String
end

ただし、この時点でタイプチェックを実行しようとすると、いくつかのエラーが発生します。

$ steep check
user.rb:11:7: NoMethodError: type=::User, method=first_name (first_name)
user.rb:11:21: NoMethodError: type=::User, method=last_name (last_name)

これらが表示される理由は、attr_readerを介して定義されたメソッドを知るために、Steepに特別なコメントが必要なためです。 s、それでそれを追加しましょう:

# @dynamic first_name, last_name, address
attr_reader :first_name, :last_name, :address

さらに、生成された.rbiにメソッドの定義を追加する必要があります ファイル。その間に、署名をanyから変更してみましょう。 実際のタイプに:

class User
  @first_name: String
  @last_name: String
  @address: Address
  def initialize: (String, String, Address) -> any
  def first_name: () -> String
  def last_name: () -> String
  def address: () -> Address
  def full_name: () -> String
end

これで、すべてが期待どおりに機能し、steep check エラーは返されません。

これまで見てきたことに加えて、Steepはジェネリックス(Hash<Symbol, String>など)もサポートしています。 )および共用体型。これは、いくつかの型の間のいずれかまたは選択を表します。たとえば、ユーザーのtop_post メソッドは、ユーザーが書いた最高ランクの投稿、またはnilを返す可能性があります 彼らがまだ何も貢献していない場合。これは、共用体タイプ(Post | nil)で表されます。 、および対応する署名は次のようになります:

def top_post: () -> (Post | nil)

Steepの機能は確かにSorbetよりも少ないですが、それでも便利なツールであり、MatzがRuby3での型チェックを想定していたものと一致しているようです。

ルビータイププロファイラー

クックパッドの遠藤裕介(Ruby開発者サークルでは「mame」としてよく知られています)は、RubyTypeProfilerと呼ばれるいわゆるレベル1タイプチェッカーに取り組んでいます。ここで紹介する他のソリューションとは異なり、署名ファイルや型の注釈は必要ありませんが、代わりに、Rubyプログラムを解析しながら可能な限り推測しようとします。 SteepやSorbetよりも潜在的な問題の発生ははるかに少ないですが、開発者に追加のコストはかかりません。

概要

誰も将来を予測することはできませんが、Rubyでの型チェックはここにとどまるもののようです。現在、.rbiで使用するための「Ruby署名言語」を標準化するための取り組みが進行中です。 ファイル(Ruby Type Profilerによってスキャフォールドされる可能性があります)。開発者は好みのツールを使用できます。 Steepを使用すると、ライブラリの作成者はすでにタイプ情報をgemと一緒に出荷できます。また、Sorbetには、TypeScript定義のDefinitelyTypedリポジトリに触発されたソルベタイプの形式で同様のメカニズムがあります。 Rubyでの型チェックの未来を形作ることに興味があるなら、今が参加する絶好の機会です!


  1. PC の動作が遅いですか?ハードウェアの交換を始める前に確認すべき 10 のこと

    コンピュータの動作が異常に遅くなったことに気付いた場合 最近では、廃品置き場に持ち込む前に確認したほうがよいことがいくつかあります。実行速度の問題はソフトウェアまたはハードウェアに関連している可能性がありますが、問題が発生する前に PC に物理的な損傷がなかった場合は、ソフトウェアに問題がある可能性があります。この記事では、コンピューターの減速の原因としてソフトウェアの問題を除外する前に、確認する必要がある事項をたどります。ほとんどの場合、ソフトウェア関連の対策で問題を解決できます .そうでない場合は、ハードウェアの交換またはアップグレードに進むことができます。 再起動 コンピュータの動作が

  2. Windows 10 で RAM タイプを確認する方法

    ランダム アクセス メモリまたは RAM は、今日のコンピューターやスマートフォンに搭載されている最も人気のあるコンポーネントの 1 つです。デバイスのパフォーマンスがどれだけ優れているか、または速いかを決定します。 RAM の最も重要な側面は、ユーザーがアップグレードできることです。ユーザーは、要件に合わせてコンピューターの RAM を自由に増やすことができます。 低~中 ユーザーは 4 ~ 8 GB RAM の間のどこかを選択します 大容量は、使用頻度の高いシナリオで使用されます。コンピュータの進化の過程で、RAM もさまざまな方法で進化しました。特に、RAM の種類が登場しました。使用し