パスワードを忘れた? アカウント作成
11092863 journal
Windows

Ryo.Fの日記: なんでやねん>PowerShellのスコープ 4

日記 by Ryo.F

いや、なんでかは解らんではないんだが…
まあ、論よりコード。

PS C:\> function f{ $a; $a=$a+1; $a}
PS C:\> $a=9; $a; f; $a
9
9
10
9
PS C:\>

関数定義で、等号の左側と最後の$aはローカル変数、それ以外はグローバル変数だ。
つまり、こう動いている。

PS C:\> function f{ $global:a; $local:a=$global:a+1; $local:a}
PS C:\> $a=9; $a; f; $a
9
9
10
9
PS C:\>

つまりこういうことか?
右辺値としては、ローカルスコープを越えてグローバルスコープまで探索する。
一方左辺値としては、ローカルスコープのみを探索し、未定義ならば、ローカル変数として定義する。

やってることは理解できるが、バグの温床だろ。

もう一つ。

PS C:\> function f{$a; $a.x = 5; $a}
PS C:\> $a = [PSObject] @{x=3}; $a; f; $a;
 
Name                           Value
----                           -----
x                              3
x                              3
x                              5
x                              5
 
PS C:\>

まあ、こうなるだろうな、とは思うが。

ちなみに、同じようなコードをRubyでは:

irb(main):001:0> def f; puts a; a=a+1; puts a; end
=> nil
irb(main):002:0> a=9; puts a; f; puts a
9
NameError: undefined local variable or method `a' for main:Object
        from (irb):1:in `f'
        from (irb):2
        from /usr/bin/irb:12:in `<main>'
irb(main):003:0>

関数定義の最初のputs aでエラーになる。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by Anonymous Coward on 2014年06月13日 7時38分 (#2620338)

    なにわけのわからんこと言ってんのこの人…。

    そもそもPowerShellって、既にもう名前にShellと入ってるのになに言ってんの?
    まさかと思うけど、仮にshで書いたとして。
    shでは、local指定もしてないのに、いきなりローカル変数ができるとでも思ってんの?
    無知って次元じゃないだろもう…。

    更に「Rubyで書いた同じようなコード」とか称するクソコードが、どう見ても同じようなコードじゃない件について。
    自分でここまで「ローカルスコープとグローバルスコープがどうたら」という駄文を書いてきた癖して、
    「Rubyで書いた同じようなコード」とか称する、読むのも苦痛なクソコードにはグローバル変数が定義されてないとかね。(笑)

    何から何まで支離滅裂だろ。
    自分がどれだけおかしな主張繰り広げてるかわからないの?

    • by Ryo.F (3896) on 2014年06月13日 8時31分 (#2620360) 日記

      そもそもPowerShellって、既にもう名前にShellと入ってるのになに言ってんの?

      いわゆる普通のシェルと、PowerShellの動きが同じなら、君の指摘は正しい。
      でも、実際には違うんだよ。

      shでは、local指定もしてないのに、いきなりローカル変数ができるとでも思ってんの?

      そんなことは知ってるよ。
      つまり、君はこういうことを言っているわけだろ?

      $ f() { echo $a; ((a++)); echo $a; }
      $ ((a=9)); echo $a; f; echo $a
      9
      9
      10
      10
      $

      君の言うように、いきなりローカル変数ができたりはしない。
      特に指定しない限り、すべてグローバル変数として扱われる。

      一方、PowerShellではそうではない。
      PowerShellでは、いきなりローカル変数ができる。

      出力結果を見れば違いは明らかなんだが、どうかね?

      無知って次元じゃないだろもう…。

      君がな(失笑)。
      いや、君は無知と言うよりは、粗忽かな(笑)。
      多少は知識があるようだからね。

      更に「Rubyで書いた同じようなコード」とか称するクソコードが、どう見ても同じようなコードじゃない件について。

      君は、最初の勘違いが激しすぎて、私の意図も誤解しちゃたんだね。

      私は、Rubyでは関数の外のスコープが勝手に参照されたりしない、と言うことを示した。
      外のスコープを参照したければ、明示的に指定する必要がある。

      一方、PowerShellは、外のスコープが勝手に参照されるのに、代入ではローカル変数が外のスコープは参照されず、勝手に変数が作られてしまう。

      粗忽な君にもそろそろ違いが解ってきただろ?

      自分がどれだけおかしな主張繰り広げてるかわからないの?

      解らない。
      君に指摘がおかしいのは、よく解るよ(笑)。

      親コメント
  • by Anonymous Coward on 2014年06月13日 9時58分 (#2620400)

    PowerShellの変数スコープは、今時珍しいダイナミックスコープなんですよ。
    (しかしよく気がつきましたね。)

    $a = $a + 1

    を処理する時は、左辺に手をつける前、ローカルの$aが生成・処理される前に、右辺を処理するので
    その時点で検索すれば、$a は既に存在するグローバルなものが見つかる。

    大昔の素朴なLispインタープリタは、ダイナミックスコープでしたが、今時のLispも、Rubyも
    レキシカルスコープです。実装が楽なのでしょうが、確かにこれは、バグの元になりますねえ。

    • しかしよく気がつきましたね。

      ちょっとした規模のプログラムを今PowerShellで書いてて気づきました。
      副作用のある関数を書いたのですが、$script:などのスコープ修飾子を書かなければいけないところと、そうでないところがあることから、ちょっと調べてみた、というわけです。

      確かにこれは、バグの元になりますねえ。

      コーディング規約として、ローカルスコープ以外の変数には必ずスコープ修飾子を付けよ、とすべきなんですかね。
      Set-StrictModeあたりで強制できるといいんじゃないかと思うんですが。

      親コメント
typodupeerror

計算機科学者とは、壊れていないものを修理する人々のことである

読み込み中...