パスワードを忘れた? アカウント作成
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。

プログラマーの力量を見極める質問 」記事へのコメント

  • 参照渡しの無い言語も広く使われている現状で、値渡しと参照渡しについて説明できないだけで入門レベルというのは厳しすぎると思う。

    参照渡しの有る言語: C++, C#, VB, Pascal, Perlなど
    参照渡しの無い言語: C, Java, JavaScript, Ruby, Python, Scheme, Haskell, Erlangなど

    それとも、原文にあるpass-by-reference(call-by-referenceではなく)というのはreference typeとかポインタとかの値渡しのことを差すのだろうか。
    しかし、C#の言語仕様では“A struct may be passed by reference to a function member using a ref or out parameter.”という文があり、call-by-referenceと同じ意味として使われている。Perldocのperlsub [perl.org]

    • 「どこかに完璧な答えがあるはず」という先入観を棄てるところから始めないと。

      例えば、参照渡し/値渡しの質問だと、「渡した先でオブジェクト(変数)の中身が書き換えられる可能性があるか、ちゃんと考えてますか?」と聞かれているようなもんなので、さすがに知ってないとまずいと思います。JavaでもStringなどは値渡し的な動作をするよう設計されていたりしますから、自分の得意な言語をベースに「私は○○を使っていたのでその場合で説明させて頂きます」とか前置きして適当に語れば良いんじゃないかと。

      フィボナッチだと「設問の文章がちょっと変ですが、○○という解釈でよろしいでしょうか?」とか確認すればOK。「曖昧なところを適当に解釈して、これで良いか、と確認する」「文章が変なので分からん。ちゃんと言ってくれ、と聞き返す」「勝手に解釈して作る」「変だから作れん、と突っぱねる」のいずれの行動を取るのかも実はチェックされてるとか。いつも完璧な仕様書が回って来るとも限らず、曖昧なところを詰めるのも仕事の内なので。
      • 確かにJavaでも渡したオブジェクトのフィールドが書き変えられると参照渡しで起きる問題と似た問題が起きますし、それは入門者より上のレベルであれば知っているべき問題だと思います。
        しかしこの問題は値型と参照型の違いに関する問題であり、これを値渡し [wikipedia.org]と参照渡しの違いとして質問するのは「開発者を評価するうえでの優れた質問」(元記事より)ではありません。

        例えば、C#において、次のように構造体SとクラスCが定義されているとします。

        struct S {public int i;}
        class C {public int i;}

        また、次のような値渡しであるメソッドが定義されているとします(refやoutが付いていないので、両者は値渡し [wikipedia.org]です)。

        • いや、どんな言語であれ、関数呼び出しの副作用や、複数の返り値を返す(ような動作をする)関数の作り方ぐらいは知ってないとまずいんじゃないか、という程度の事ですが。

          対話してるんだから面接官もちょっとはヒントとかくれるでしょう。「値・参照渡しの違いを説明してください」「聞いたことのない単語です」「得意な言語は?」「Cです」「じゃあ、scanfの引数に&を付ける理由を説明してください。もしくはaとbを入れ替える関数swap(a,b)のような物の作り方を説明してください」みたいな感じで。それを「面接で聞くべき質問」というタイトルで簡潔な文章に
          • 少なくとも、Java, C#, Javascript, VB.NET, その他多くのプログラミング言語では参照型のオブジェクトもデフォルトでは値渡し [wikipedia.org](つまり参照の値渡し [wikipedia.org])で渡されます。

            例えば前のコメント [srad.jp]のvoid f(C c)においてクラスCは参照型ですが、値渡しされます。これを参照渡しにするためにはvoid f(ref C c)と書きます。
            他にもPHPにも参照渡し(passing by reference)はあります [php.net]が、マニュアルのObjects and referencesという節 [php.net]では

            • by Anonymous Coward
              > > あとまあ、特に何も指定しないと、値型のオブジェクトは値渡しされ、参照型のオブジェクトは参照渡しされるわけで、

              彼は参照渡しと、参照値の値渡しの区別がついていないようですね。というか参照渡しの存在を知らないように見えます。
              そもそも参照型のオブジェクトという言い回しからして病根の深さが。あなたも釣られちゃだめですよ。

              void f(C c) { c = null; } // 値渡し

              void g(ref C c) { c = null; } // 参照渡し

              void main(void) {
                C c1 = new C(); // c1は参照値
                f(c1);
                print c1;

                C c2 = new C(); // c2も参照値
                g(c2);
                print c2;
              }
              • >彼は参照渡しと、参照値の値渡しの区別がついていないようですね。

                あら、そう取られちゃいましたか。g(c2)の呼び出しはref付ける必要がありませんか?

                言葉の厳密な定義はどうでも良くて(厳密な定義を尋ねたいわけじゃなくて)、面接対象者がプログラマとして必須なある種の概念を理解して使い分けられるかどうか、それを聞いてるのがこの設問のポイントに違いない、と頑張って書いたつもりだったので、どうでも良い部分は適当に書き流してました。

                例示されたプログラムを見せて「gの定義にrefと付いてるのはなぜか(どういう場面で付けるべきか)?」「gの呼び出しにはなぜrefが要るのか(要るという文法に設計されているのか)?」とか聞いてみるのもアリなんじゃないでしょうか。
                親コメント
              • by Anonymous Coward
                > g(c2)の呼び出しはref付ける必要がありませんか?

                おお、C#はそうですね。

                > 言葉の厳密な定義はどうでも良くて

                おっしゃる通りです。わたしがgの呼び出しにrefを付け忘れたのはこちらの範疇です。C#固有の文法的な問題で、PascalやC++をはじめ大抵の言語では不要ですし。

                > 面接対象者がプログラマとして必須なある種の概念を理解して使い分けられるかどうか、

                プログラマとして必須かどうかは知りませんが、少なくともあなたは理解していません。つまり

                > 「gの定義にrefと付いてるのはなぜか(どう
              • >> 「gの定義にrefと付いてるのはなぜか(どういう場面で付けるべきか)?」「gの呼び出しにはなぜrefが要るのか(要るという文法に設計されているのか)?」とか聞いてみるのもアリなんじゃないでしょうか。
                >ではなく、「gの本体で引数のcへ直接代入しているのはなぜか?」というのが値渡しと参照渡しの最大の違いだからです。
                今ひとつおっしゃる問題点がぴんと来ません。「gの定義にrefと付いてるのは?」と「gの本体で引数のcへ直接代入しているのは?」は同じ事を逆から聞いているだけに思うのですが。疑問文じゃなくしたら互いの答えになりますし。

                Q.「gの定義にrefと付いてるのは?」→A.「gの本体で引数のcへ直接代入したいから」
                Q.「gの本体で引数のcへ直接代入しているのは?」→「gの定義にrefと付ければよい」

                もう一つ例示した「gの呼び出しにrefが要るのは?」の方の答えは、まさにそのバグに注意をさせるためですよね。

                例えば、pがリスト構造になっている何かだとして、

                void recurse(ref List p){
                if(p == null) return;
                p = p.next;
                recurse(ref p);
                print(p);
                }

                とか再帰呼び出しを行うとpの最後の要素だけがpの長さ分だけ表示されちゃうとか。「普通の呼び出しとは違って、ここでpが変わる可能性があるよ!」と注意させるためのref付け必須。

                さらに話が逸れますが、呼び出し部分を見ても値渡しか参照渡しか分からない言語で、まさにこの構造のバグ(もう少し複雑な処理をするプログラムでしたがもちろん)に悩んでいる人を見たことがあったので、なかなか面白い試みだと思いました>呼び出し側のref付け。
                親コメント
              • by Anonymous Coward
                > 今ひとつおっしゃる問題点がぴんと来ません。「gの定義にrefと付いてるのは?」と「gの本体で引数のcへ直接代入しているのは?」は同じ事を逆から聞いているだけに思うのですが。

                例えば古いFORTRANは参照渡ししかできません。引数の宣言にrefをつけるといったことは言語に依存するわけです。
                つまり前者はC#固有の話ですが、後者は言語によらない話です。

                > もう一つ例示した「gの呼び出しにrefが要るのは?」の方の答えは、まさにそのバグに注意をさせるためですよね。

                おっしゃるとおり過去の反省からC#ではgの呼び出し側でも引数にrefをつけるようになっています
              • >つまり前者はC#固有の話ですが、後者は言語によらない話です。

                なるほど。そこは面接官が文脈に応じて適当に言い換えることを想定していました。ツリーの上の方からの流れで「あなたはC#が得意だそうなので、C#の話をしましょうか」という合意が取れた後を勝手にイメージしていたもので。

                >値渡しや参照渡しといった概念は特定の言語とは独立していますから、いずれも面接官の問いとしては少なくとも不十分です。

                結局、不十分なら適当に補えば良いんじゃないか? そういう概念を理解出来ているか確認するのは悪いことではないんではないか? と思っただけです。
                親コメント
              • by Anonymous Coward
                > 結局、不十分なら適当に補えば良いんじゃないか? そういう概念を理解出来ているか確認するのは悪いことではないんではないか? と思っただけです。

                ちゃんと補えれば100点で、概念の理解の確認にとどまれば80点くらいなりということです。

                たとえば、正規表現はあなたも十分ご理解なさっていると思います。少なくともプログラムを書く際に困らない程度には。
                しかし、もしあなたがオートマトンについてご存知ないとしたら、オートマトンは理解しているが正規表現を知らないプログラマと意思疎通できるでしょうか?さんざん議論したあげくに「なあんだ」ということにならないでしょうか。
              • まあ、さすがに面接官ともなれば、ちゃんと分かってて(例示された例だと、正規表現、正規言語からオートマトンまでの流れを全部分かっててどこが話題になっても対応できる状態で)聞くでしょうから、話がかみ合わずにぐだぐだに終わる心配はしなくても良いような気がしますが楽観的すぎますかね。
                親コメント

未知のハックに一心不乱に取り組んだ結果、私は自然の法則を変えてしまった -- あるハッカー

処理中...