トップページ⇒tech
788コメント352KB

型なし言語逝ってよし

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
Perl, JavaScript もろもろ型のはっきりしない言語は逝ってよし
0666デフォルトの名無しさんNGNG
>>665
実行時というか、コード入力している段階でデバグを
同時進行できるのが利点なんじゃない?
(段階を踏む必要が無いって意味)
例えばlisp/schemeは暗黙の型キャストなんかは無いけど、
必要なデバグのテンプレートなんかその場で簡単に作れるから、
開発サイクルがとても早い。
目的、手段に簡単にアクセスできるって感じがいい。
完成品をいち早く見れる出力の代替能力が高いからなんだけど。
0667デフォルトの名無しさんNGNG
型なし言語は処理系を作る段階で
テスト用ソースを書いていてドツボにはまる、と書いてみるテスト。
0668デフォルトの名無しさんNGNG
>>667いみわからん
0669デフォルトの名無しさんNGNG
>>668
コード生成部のバグとりがかなり死ねるような、と思ってみた。
0670デフォルトの名無しさんNGNG
>>659
UnitTestもできるしな、ってのは視野狭窄な話だな。UnitTestできない言語なんぞあるのか(笑)
UnitTest用のフレームワークがまだ用意されていない言語ならあるかもしれないけど、よほどマイナーじゃないとね。
0671えとNGNG
バリアントあげ!
0672デフォルトの名無しさんNGNG
Perlって本当に糞言語だよな。sage!
0673デフォルトの名無しさんNGNG
Rubyさいこー
0674デフォルトの名無しさんNGNG
Ruby以外の言語は糞言語。これ決定
0675デフォルトの名無しさんNGNG
自作自演Rubyあげー
0676デフォルトの名無しさんNGNG
Ruby!
0677デフォルトの名無しさんNGNG
Perlは、はっきりいって糞だよ。Rubyほどじゃないけど
0678デフォルトの名無しさんNGNG
Rubyは最高の言語!
0679デフォルトの名無しさん NGNG
つかperl使うと馬鹿になるYO!! Rubyほどじゃないけど
0680デフォルトの名無しさんNGNG
でもインタプリタってどれも糞なんじゃないの?Rubyほどじゃないけど
0681デフォルトの名無しさんNGNG
あらゆる言語は糞言語。Rubyほどじゃないけど
0682デフォルトの名無しさんNGNG
COBOLとかの終わってる系は嫌だね。Rubyほどじゃないけど
0683デフォルトの名無しさんNGNG
>>669
正解。かなり死ねる。っていうか実際死んだ。
お前の腕が悪いだけだ!、と言われたら反論できないけど(w
0684デフォルトの名無しさんNGNG
>>683
お前の腕が悪いだけだ!
0685デフォルトの名無しさんNGNG
>>679 つか、変数に型がある言語では、
   ソースコード上の変数追っかけていけば、データの流れが追いやすいけれど、
   値のみに型がある言語では、実行時のデータの流れを想像する必要があるから疲れる...
   俺の型推論神経が退化してくる...
06860x7c3NGNG
思いついた!

デフォルトだと型無しだけどモード設定みたいなので
型有りになる言語ってどーよ。

たとえて言うならVBに変数定義強制&&バリアント型使用不可&&
subとfunctionの引数と帰り値の型指定強制するモードを付ける感じ。

とりあえず型無しでコード書いて落ち着いてきたら型有り
(型無しになってる部分を発見するとエラー出す)モードにして
細かいところをつめていくの。

これなら型無し言語と型有り言語の良い所を併せ持つ感じに
なると思うんだけど。

どうよ。
0687デフォルトの名無しさんNGNG
>>686
形無し指定した変数のからんでるところで、同じようなことになると思われ。
06880x7c3NGNG
>>687
たとえばどんな例が考えられますか?
0689デフォルトの名無しさんNGNG
>0x7c3
医院でないの?現にInterDevとかではnew ActiveXObjectした直後(JScriptの話ね)
とか関数の戻り値なら型情報を考慮してくれるし、それをもっと適応範囲を広くして
便利にしたらMSが買収してくれるよ(藁
0690デフォルトの名無しさんNGNG
>>686
数年前の話しだけど、JavaScriptがいちいち型を気にしなくて良いから楽だなぁ、
などとうかつにも考えてしまっていたとき、C/C++にany型を導入するというアイディア
をもったことがあったよ。このとき、単純にany型を導入するんではなく(そんなの
なら別におもしろくも珍しくもなんともない)、段階的にany型を解消することで
プログラムが型の扱いに関して成長していくというもの。君の考えといっしょ。

思考実験の結果、かなり強力な型推論機構が必要だと考えた。
また、その強力な型推論機構C/C++の型のシステムに融合させるのは
完全には無理で、なんらかのランタイムデバッグサポートが必要。

any型を引数にもつ関数は、過去に呼び出されたときの(もしわかるならば)実際の型が
何であったか記録しておき、その型とそのスーパータイプ以外で呼び出された
ときには通知する、といったデバッグサポートがあると便利だろう。その情報は
後にany型の型を制限するようなコードを追加するときに利用する。そして
ある程度開発が進んで型情報のデータがたまったら、それをもとに型を固定してしまう。

デバッグを終えプログラムをリリースしてしばらくしてから、こんなエラーが
でましたけど…、という報告が入り、急きょデバッグすることになる。
まず、その異常な型が発生する状況を再現するのに苦労する。
なんとかデバッグできるようになっても、型の融合に苦労する。
テンプレートみたいなのでうまくお茶を濁せればラッキーで、
結局any型はいつまでも残る。ちっとも段階的に解消しない。

「段階的に〜」というところは結局any型を導入しただけで終わり、
今後の愁いをなくすためにany型はany型として残すようになって、
そのままリリースして終わるだろうなぁ、というところに落ち着いた記憶がある。
0691デフォルトの名無しさんNGNG
つーか、ほれ、変数が宣言なしに使用できて、
最初に代入したときに型がフィックスされて、
異なる型の値を代入しようとしたり、
代入する前の未定義状態のまま値を評価しようとしたりすると例外を投げる、
みたいなのでけっこう十分に実用的だと思うんだよな。
まあ、そうすると実行時型チェックが必要になるから、遅くなると
言えば遅くなるね。でも、そういうときには静的に変数宣言すれば、
型チェックされないみたいな言語仕様にもできるでしょ。
Objective-Cでそういうテクニックが使えるよな。
0692デフォルトの名無しさんNGNG
>>691
>代入する前の未定義状態
こんな状態作らなければよいじゃん。そもそも、
>変数が宣言なしに使用できて、
これにメリット無い。
0693デフォルトの名無しさんNGNG
>>変数が宣言なしに使用できて、
>これにメリット無い。
禿同。
Pythonみたいに、最初の代入が宣言として扱われるのはいいとして、
PHPや昔のBASICみたいに、最初に参照されたときにデフォルトに
初期化されるのは、デメリットだけだね。
06940x7c3NGNG
長文失礼。

>>690
僕は趣味で書くコードをRubyでとりあえず書いて後から
ANSI-Cで書きなおすって事をやったりするんですけど、
その時に「同じ言語で書けたら少しは楽になるかなぁ。」
とか思ったり、異論は有ると思いますが
型無しはプロトタイプ作るのに便利だけど遅かったり予想外の事が起きやすい。
型有りはコードを書き始めてから動くまで時間がかかるけど、ちゃんと作れば早いしエラーも起きにくい。
ということで、双方の良いところを併せれば良い言語が
出来るんじゃないか? と思って>>686を思いついたんです。

でも、実際に仕事なんかで使うとなるとやっぱり
>今後の愁いをなくすためにany型はany型として残すようになって、
>そのままリリースして終わるだろうなぁ、というところに落ち着いた記憶がある。
と、こういうことが起こりそうですよね。

#現実は甘くない、と。


>>693
禿同。

変数は宣言必須のほうが良いと思います。
まぁ、最初は警告出すだけにしといて型有りにしたら
エラーにするってのも有りだと思いますけど。

#宣言してない変数って使ってることすら忘れそうだし。


##趣味プログラマ暦10年ちょっとの俺では経験が足りないか。ウツー
0695デフォルトの名無しさんNGNG
宣言必須、初期化必須にしても、それは本質じゃないんだよな。
未定義(初期化されていない)の変数が参照されるってことは、
ロジックのどこかに問題があることなんで、エラーが出るべき
なんだ。初期化されているからといって、それが意味のある値
とは限らない。「とりあえず」の値に過ぎない(プログラム開
始時には意味のある値を決められない)変数ってあるわけです
よ。

# たとえばparserにtokenを渡すscannerを書くとして、入力
# を受け取る前の現在のtokenは未定義であるべきでしょう?
# 未定義であることを示す特殊な値を定義することもできます
# が、正当な使い方であるかぎり、入力を受け取る前の
# scannerに対してtokenを要求するのはおかしいわけですか
# ら、例外が投げられるべきです。そして、それはscanner側
# の問題ではなく、scannerにtokenを要求する側(この場合
# はparser)の問題でしょう。

宣言必須にすることのデメリットは他にもあって、基本的に変
数の型を宣言することは、冗長な作業ですよね。たとえば型推
論の機能があれば、ある変数に複数の型が代入されていること
をコンパイル時に検出してエラーを出すことはできるわけです
から、わざわざ手作業で型宣言させる必要はないと思います。

# ないしはソースコードを静的に型チェックするチェッカーを
# ユーティリティとして用意し、デバッグ中にこれを使用する
# のでもかまわないと思いますけれど。
0696デフォルトの名無しさんNGNG
>>695は話の流れを理解できないアホ。
0697デフォルトの名無しさんNGNG
>>694までの流れで言うと「初期化」は、明示的な、プログラムとして意味のある初期値の代入と思われ。

また、型推論で2種類の型がバインドされる可能性が見つかったとして、
その2つのうち「どちらかが必ず正しい」とjは限らないわけで。

それから、strong typedな言語で、型宣言しておけば、自動的な型変換が期待できる場面で、
わざわざ明示的な型変換を書くのは冗長な作業だと…
0698デフォルトの名無しさんNGNG
>>695
パーサがスキャナに、最初に「次のトークンをくれろ」っていう構造は、間違っていると?
つまり、
「まず、最初のトークンをとりだしてちょ」ってしてから
「次のトークンをくれろ」を繰り返せ、と??
0699デフォルトの名無しさんNGNG
>>698
いいえ。最初から「次のトークンをくれ」で良いんです。
でも、トークンの値は入力を評価するまでは決定しないですよね。
0700デフォルトの名無しさんNGNG
698>>699
う〜ん、スキャナとパーサに限って言うと、パーサから「次をくれ」って言われて初めて、
スキャナがトークンの取りだしをはじめるのが一般的だとおもうからなぁ。
あんまり良い例ではないのかも。
0701デフォルトの名無しさんNGNG
>>700
いや、だからさ、最初に「次をくれ」って言われるまでは、
トークンの取り出しは始まらないだろ? 取り出してないん
だから、取り出した値の格納先は未定義だよね?
0702デフォルトの名無しさんNGNG
っつーかさ、
それで「まだトークンがないから」例外投げるなんて...
普通はブロックするだろ。
0703デフォルトの名無しさんNGNG
>>701
だからさ、取り出しが始まったら未定義じゃなくなるんだから、
未定義なものを参照するやつが居ないじゃん。
ちみ、自分で
>入力を受け取る前の
># scannerに対してtokenを要求するのはおかしいわけですか
># ら、例外が投げられるべきです。
って書いたの忘れてる?
0704デフォルトの名無しさんNGNG
これはどうですか?
http://fa.puresilk.ac/idol/
http://fa.puresilk.ac/idol/nozoki.html
0705デフォルトの名無しさんNGNG
>>701は、字句解析と構文解析の区別がついていないと思われる也
で、変数の宣言を必要としないのは、デメリットの方が大きそう。
ということで、

1、型を変数と同時に宣言する、このときany型のような宣言が出来る。
2、型は宣言しない、特に型を強くしたい変数のみ、型を宣言しとく。
3、型は最初の代入で決まる、以降は型チェックが実行時に行われる。
4、宣言は3と同様、実行前に型推論でチェックされる。

などいろいろありそですが、話、もとにもどりそうですか?
0706デフォルトの名無しさんNGNG
>>703
だから宣言するときに初期化できないでしょ、という意味なんですが。
0707デフォルトの名無しさんNGNG
>>705
テスト段階は3、コンパイルすると4ってのがいいです。
0708デフォルトの名無しさんNGNG
!!!!!!!!!!!!!!!!!!!!!
>>704はブラクラ(正確には違うが)
!!!!!!!!!!!!!!!!!!!!!
0709デフォルトの名無しさんNGNG
>>706
なんか、毎回主張が違ってるようですが。
0710デフォルトの名無しさんNGNG
ageageage
0711デフォルトの名無しさんNGNG
なんかアホが一人いたみたいね。
具体的に言うと>>700のことなんだけどさ
0712デフォルトの名無しさんNGNG
宣言ウザいっていう意見はさ、
宣言のあるなしじゃなくて
宣言の自由度と、宣言の結果の変数のスコープについて
考えるべきだと思うんだよね。
実際、C++の
「for(int i=0;i<10;i++){}」
っていうコードはかなり便利だし、
それ覚えて後でpure cいじるとすげえうっとうしく感じるもの。
0713デフォルトの名無しさんNGNG
>712
C99 may make you happy!
0714デフォルトの名無しさんNGNG
>>711
おやおや、今度はアホよばわりですか?
いいかげん宣言と初期化の分離を認めたらどうですか?
0715デフォルトの名無しさんNGNG
あげてみよう!
0716デフォルトの名無しさんNGNG
型あり派の方々は参照透過性の問題についてどう考えていますか?
僕は型にこだわらない方ですが、関数型言語じゃない言語を使って
るときでも、初期化以外の代入を避けたりしてますけど。
0717デフォルトの名無しさんNGNG
参照透過性と、型あり/型なしの関係って、とっても薄いんでは内科医?
0718デフォルトの名無しさんNGNG
いやさあ、型チェックのおかげで検出できるバグってどの程度のものか、
とか思うわけよ。
参照透過性を確保する方がバグをなくすのに貢献するというのが俺の実
感なんだけど、みんなはどうかなあ、とか。
というか、参照透過性を確保するようにコードを書くと、型の問題が小
さくなりません? とか思うんですが。
0719デフォルトの名無しさんNGNG
age.
0720デフォルトの名無しさんNGNG
>718
>参照透過性を確保するようにコードを書くと
Cでサンプル書いてみてよ。
0721デフォルトの名無しさんNGNG
手続き型で参照透過性を保とうとするっていうのは
出来るだけ特定の状態に依存しないようにするっていうことで
それがバグの発生を減らすことになるんでしょ。

でも
int a = 3;
a + 10; // ここでの値
a = 4;
a + 10; // と、ここでの値
が同じでないっていうのは(これだけでも)参照透過性が失われてるような感じだし
やっぱ手続き型で参照透過性云々っていうのは違和感がある。

あと、型あり/型なしとは関係ないような…。
0722デフォルトの名無しさんNGNG
>>717>>721
関係無いに1票。

あと、参照透過性を確保する書き方と、
参照透過性を保証した言語との、近そうで
とっても遠い関係に気がついてない人が
いるに、自分で1票。
0723こんな感じ?NGNG
// Cによる山椒投下サンプル
#include <stdio.h>
#include <malloc.h>

int *swap2(int arr[])
{
 *ret = malloc(sizeof(int[2]));
 ret[0] = arr[1];
 ret[1] = arr[0];
 return ret;
}

int main()
{
 int arr[2] = { 1, 2 };
 int *rev = swap2(arr);
 printf("%d,%d", rev[0], rev[1]);
 return 0;
}

こんなんでquicksortやったら凄いことになりそうだな...
0724デフォルトの名無しさんNGNG
>>723
代入の代わりに新しい変数作ってたら…
0725デフォルトの名無しさんNGNG
>代入の代わりに新しい変数作ってたら…
計算の過程が全て残って楽しいかも(藁
0726717NGNG
>>723-725
まー普通は、
・動的エクステントが必要か、静的エクステントで充分か検討して、
・後者ならばスタック上に変数をアロケートする (alloca(3)参照)
んじゃないかな? (戻り値のサイズを呼び出し側で指定するのは面倒だけど)

>>716
参照透過性 と 型あり/型なし
プログラムの静的解析に貢献するって点が共通点?
んでも、型ありで参照透過性なしだったら、静的解析しにくいでしょ。

すると、>>723 は何をしたいのか、いまいちよくわからん。
0727デフォルトの名無しさんNGNG
まぁー>>718は、純粋関数言語派としては、至極まっとうな意見かと。

でも、モナー度のC言語的解釈をするのが先決かと。
0728デフォルトの名無しさんNGNG
バグがどこに潜むのか、ってのが問題でしょ。

静的な型システムがバグの検出に役立つってのは、
関数の戻り値を型の異なる変数に代入しようとしたりするのを
コンパイラが検出できるってことだよね?

ある変数に対する代入が1回しか行われないなら、
その変数に格納される値の型は一意に決定できるわけでしょ。
でもって、あらゆる関数の戻り値の型が一意だとしたら、
変数の型を宣言することは冗長だよね。

型なし言語でも自衛することはできるって話です。

# もちろん必要があって様々な型をとる変数を使うのは
# いいんですよ。そこが急所だってこともわかってるだ
# ろうし。
0729デフォルトの名無しさんNGNG
>>728
> その変数に格納される値の型は一意に決定できるわけでしょ。
多相型(parametric polymorphism, inclusion polymorphism, ad-hoc polymorphism)
どの多相型も、静的型付で代入が1回のみであっても一意に型が決まらない。

> # もちろん必要があって様々な型をとる変数を使うのは
> # いいんですよ。そこが急所だってこともわかってるだ
> # ろうし。
動的型付にしろ、静的型付+多相型にしろ、
それは急所ではなく、長所であり要所となる。
0730728NGNG
>>729
参照透過性が確保されているなら、ある式の型は静的に決定できるよ。
多相型をサポートする関数であっても、関数に与える引数の
型が静的に決定できれば、戻り値の型も静的に決定できるでしょ。

急所っていうのはHot Spotの訳語のつもりで使ったんだ。
要所と言い換えてもいいです。混乱させてスマソ。
0731デフォルトの名無しさんNGNG
>>730
「要所」については了解。
折れは多相型や動的型付は欠陥ではなく、逆に武器になるということだけ言いたかった。

型を決定できるかどうかについては、例えば、こんな場合はどう思う?
1. parametric polymorphism
 id x = x
 ここで、「=」の右側に出てくる「x」の型は?

2. inclusion polymorphism
 Shape something() {
  if (rand() > 0.5)
  return Point(0, 0)
  else
  return Rectangle(0, 0, 0, 0)
 }
 さあ、この関数sample()の返値の型は?答えはShape。
 では、この関数から返されるオブジェクトの型は?
 また、以下の場合、
 Shape something() {
  Shape s;
  if (rand() > 0.5)
  s = Point(0, 0)
  else
  s = Rectangle(0, 0, 0, 0)
  return s;
 }
 変数sが指すオブジェクトの型は?

3. ad-hoc polymorphism
 加算演算子「+」に文字列演算子「+」がオーバーロードされているとして、
 a ++ b
 の型は?
 aやbがinclusion polymorphismの2番目の例に出たような形で決定されていたら?
0732731NGNG
補足と訂正。
1.の関数idは、id 1 = 1, id 'abc' = 'abc'となるような関数。
2.では、PointとRectangleはShapeのサブクラスとして読んでくれ。
3.の
> 加算演算子「+」に文字列演算子「+」がオーバーロードされているとして、
> a ++ b
> の型は?
は、
> 加算演算子「+」に文字列連結演算子「+」がオーバーロードされているとして、
> a + b
> の型は?
に置き換えてくれ。スマソ。
0733デフォルトの名無しさんNGNG
>>728
変数の型を一意に決めるのは、変数宣言のときだけではなく、
初回の代入のときでもいいし、
すべての代入をリストアップして、合う型を調べてもいい。
型あり言語では、代入の度に変数の型が変わるようにはしないので、
代入が1回だけじゃないと型が決まらないわけではない。
0734728NGNG
1については意味がわかりません。右辺のxはそれ以前に値が
決まっているのではないの?
2のような関数は参照透過性を確保しているとは言えないでしょ。
3については、この文脈だけではわからないけれど、前後のコード
から型を決定できると思いますが。
0735733@Lisp初心者NGNG
(defun foo (n) (if (= n 0) "zero" n))

この関数は参照透過性が確保されている関数という認識でいいんだよね?
0736731NGNG
2では2つ関数を定義したけど、
1つ目は代入は一切なし。
2つ目は2つ代入文があるけど、どちらか一方しか実行されない。
つまり1回しか代入しない。
したがって参照の透明性は確保されているよ。
0737733NGNG
rand() がまずいかと…
0738731NGNG
>>737
そうね、rand()はまずいね。スマソ。
じゃ、引数に適当な整数を取って、それが0か非0かで分岐するってことで。
つまり>>735と同じ問題に帰着する。(735は動的型付、731は静的型付という違いはあるが)

実行コンテキストにおいて具体的な実パラメータが確定しなければ
関数の実体における仮パラメータを用いた式の型を確定させることはできないっしょ?

あ、ひょっとして実行コンテキストが確定して、今まさにその式を評価しているという時の話?
0739728NGNG
わざわざ静的な型決定ができなくなるような書き方をする場合に、
参照透過性を云々するのって奇妙な気がするんだけど。
MLにおける多相のようにすれば、静的に型決定できるわけで。
0740731NGNG
>>739
そのMLにおける多相ってのが>>731の1. parametric polymorphismなんだけど…
つまり型変数を使って任意の型の値を扱えるようにしたりとか(parametric polymorphism)
subtypeを使って型階層の部分木の任意の型の値を扱えるようにしたりとか(inclusion polymorphism)
演算子(または関数)オーバーロードや暗黙的型変換を使って複数の型の値を扱えるようにしたりとか(ad-hoc polymorphism)
参照の透明性があっても、ある変数が指す値(オブジェクト)の型は一意に制限されることはなく、
多様な値を取ることが出来る、ってこと。
0741728NGNG
だから静的に型決定できるようにコーディングして、
参照透過性を確保することはデバッグしやすさに寄与
するでしょ。731は何がいいたいの?
0742731NGNG
>>741
静的に型決定できることと参照透明性は直接関係ない。
すなわち参照透明性を保障しても型は一意に決定できない。
また、型が一意に決定できることはデバッグしやすさに寄与しない。
MLの多相型などは型を一意に決定しないことで再利用性を確保し、
多相型に基づく型推論によってデバッグを支援している。
0743728NGNG
>>742
まあ、そうなんだけど、静的に型を決定できるようにコーディング
することはできるし、また、参照透過性を確保するようにコーディ
ングすることもできる。そのようなコーディングをすることがデバッ
グしやすさに貢献すると俺は考えているんだよ。

「型が一意に決定できることはデバッグしやすさに寄与しない」
ってのはどういう根拠によるの?
動的に型が決定する言語の場合、実行時にメソッドディスパッチ
するまで、そのメソッドの正当性を決定できないでしょ。それが
動的に型を決定する言語のメリットかつデメリットな部分だよね?
意識してメリットを享受している場合は良いけれど、無意識にデ
メリットをかぶるのは困るわけ。
それで、僕は、僕なりに動的に型を決定する言語においても、型
を静的に決定できるようなコーディングスタイルを励行すべきだ、
と考えているのだがね。参照透過性についても同様です。
0744731NGNG
>>743
> 静的に型を決定できるようにコーディングすることはできるし、
これは確かに可能ではあるよ。でもさ、これをやっちゃうと行き着く先はどうなるかというと、
「関数(メッセージ式)の返り値の型が一意に決定できるようにするためには、
関数(メッセージ式)の型が一意に決定できていなければならない。」
これが何を意味するかというと、
オブジェクト指向言語では、継承を放棄しなければならないということになる。いいの?
そこまで極論しなくても、メッセージ式の返り値の型を一意に決定できるようにするには
メソッドを定義するときには既存のメソッド名とは別の名前をつける必要があるよね。
それって、オブジェクト指向とは逆行するものだと思うよ。
例えば適当なSmalltalkの処理系、とりあえずSqueakでもいいや、
「at:」という名前のメソッドを列挙すると46個あったりするけど、
これはat:という名前から46個のメソッドが有り得てしまうという「混沌」かな?
それとも、46個の異なるメソッドを1つの名前に統一する「秩序」かな?
返り値が何だか全然わからないという点では「混沌」かもね。
でも、その「混沌」を排除しようとすると、「秩序」を破壊してしまって、
「さらなる混沌」が待っているよ。
0745731NGNG
> 「型が一意に決定できることはデバッグしやすさに寄与しない」
> ってのはどういう根拠によるの?
「1つのバグの潰しやすさ」を「デバッグのしやすさ」とするのなら
多少は寄与する部分もあるかもね。しかし、
「1つのプログラム中のバグの数の減らしやすさ」を「デバッグのしやすさ」と捉えれば
関数(メソッド)の型を一意に決定することは逆効果だよ。
関数の型を一意に決定することは再利用を妨げることになり、
結果的にバグが混入する可能性を高めることにしかならない。
0746731NGNG
sage忘れた。スマソ。

で、長くなっちゃったけど、
デバッグしやすいコーディングスタイルを模索することは素晴らしいことだと思うし、
無用な破壊的代入を減らすことはよいことだと思う。
しかし、それを「型を一意に決定する」に繋げるためには、
あまりにも大きな代償を払わなければならないし、
あるいはその代償を払わずに「型が一意に決定されている」という
誤った幻想を持つことも危険だよ。
0747横レスNGNG
>こまで極論しなくても、メッセージ式の返り値の型を一意に決定できるようにするには
>メソッドを定義するときには既存のメソッド名とは別の名前をつける必要があるよね。
>それって、オブジェクト指向とは逆行するものだと思うよ。
>例えば適当なSmalltalkの処理系、とりあえずSqueakでもいいや、
>「at:」という名前のメソッドを列挙すると46個あったりするけど、
>これはat:という名前から46個のメソッドが有り得てしまうという「混沌」かな?

総称は本来静的な考え方でしょ。同名の関数(メソッド)がいくつあっても
コンパイラや解釈系がどんな型へのメッセージかを一意に決定できて、別のものになる。
ソースコードのレベルで多相を実現しているに過ぎない。静的型の技術を用いている。

>「1つのプログラム中のバグの数の減らしやすさ」を「デバッグのしやすさ」と捉えれば
>関数(メソッド)の型を一意に決定することは逆効果だよ。
>関数の型を一意に決定することは再利用を妨げることになり、
>結果的にバグが混入する可能性を高めることにしかならない。

再設計とかリファクタリングの話をしているの?「型を一意に決定する」って
「オブジェクト指向な開発スタイルなのに、全部最初に矛盾なく決めてからやる」
ってことじゃないですよ。
0748747NGNG
すいません、過去レス読んだら、議論の最中に>>747みたいな蒸し返しレスを
入れちゃうパターンが延々と続いてましたね。これからは気を付けます。
0749728NGNG
731が言っているのはあれでしょ、総称的な関数とか、
戻り値が多様な型を持つ関数が見通しの良いコードに
貢献するってことでしょ。それは認めるよ。
でもさ、総称的な関数は、引数から戻り値を決定でき
るわけでしょ。たいていの場合は戻り値の型は容易に
推測できるよね? 容易に推測できない=慎重に使わ
ないと危険な総称的関数など、誰も使いたがらないだ
ろうし。
0750デフォルトの名無しさんNGNG
>>749
> でもさ、総称的な関数は、引数から戻り値を決定できるわけでしょ。
じゃあ、引数の型はどうやって決定する?
その引数の値を作った関数適用(メッセージ送信)の引数の型から?
じゃあ、そのまた引数の型は?
ってなことが延々と続くなり。

どっかでリテラルコンスタントにあたって型が決定できたとしても、
今度は>>731の2. inclusion polymorphismの例のようなコードはどうする?
あるいはAbstract Factoryなんかもいい例かもしんない。
ちなみに>>731は静的型付けしている場合の例だよ。
動的型付け言語では、もっとエキセントリックな事が極自然に行われる。

>>747
> 同名の関数(メソッド)がいくつあっても
> コンパイラや解釈系がどんな型へのメッセージかを一意に決定できて、別のものになる。
???
メソッド選択の話?
変数の型ではなくオブジェクトの型から決定しているところからしても、
いかにも動的型的だと思うのだが…
静的型の処理系であっても、いわゆるvirtualなメソッド探索なら
すごく動的言語的じゃない?
0751デフォルトの名無しさんNGNG
型あり言語が総称を使った場合に戻り値の型が容易に推測できるのは、
戻り値の型を明示しているから。
template<class T> T min(T a, T b) { return (a < b)? a : b; }

引数a、bと戻り値の型がTであり、同じ型だということを示している。
型なし言語の場合、明示しないから、戻り値の型は容易には推測できない。
0752デフォルトの名無しさんNGNG
> 引数a、bと戻り値の型がTであり、同じ型だということを示している。

ダウト。正確にはTまたはTのサブタイプ(サブクラス)。
したがってその返り値にvirtualなメッセージ送信をした場合には
どのメソッドがディスパッチされるのかは確定できない。
保障されるのは、「対応するメソッドが存在する」ということだけ。
0753728NGNG
動的な言語でコーディングするときは、しばしば変数名で
その変数の型を表現するよね。

aObject = Object::new()

クラス名を利用することもあるし、

if prodocut.code == target.code
  return product.price
end

メソッド名を統一したりして、使うことも多いね。

もちろん、そういうコーディング規則では不十分なケースも
時々あります。でもね、たいていの場合は十分なんでありま
して、UnitTestを併用するなどして動的な型付けの言語でも、
型の不一致で予想外の挙動になることを避けることはできる
わけですよ。

で、僕が728で言ったことは「静的な型付けのおかげで回避
できるバグってどの程度のもの?」ということなんだけど、
悪いけど、ここで述べたようなコーディング規約で回避でき
る程度のバグだけなんじゃないの? って気がするわけ。

# ハンガリアン記法など、変数名で型を表現しているわけで、
# 静的に型を決定する言語においても、そのようなコーディ
# ング規約が有用であることを示していると思いますけどね。
0754751NGNG
>>752
継承も一緒に議論されているので、そっちの方が良かったですね。
あと次のような場合、その言い方であっているかわからなかったので。

class A {};
class B : public A {};

A& foo() { static B b; return b; }
char* bar(A a) { return "a"; }
char* bar(B b) { return "b"; }

void main() {
puts(bar(foo()));
}
0755751NGNG
>>753
私の場合、C言語ではアドレス演算子の付け忘れや、
ポインタ演算子の数の間違えなどのイージーミスを
エラーにしてくれるので、非常に助かっています。
っていうか、このスレを頭から「ミス」で検索してみるのがよいかと。
0756728NGNG
>>755
ありがと。でも、アドレス演算なんかそもそもバグの温床では?
0757751NGNG
>>756
構造体を関数に渡すときに、変数のアドレスを渡す。foo(&record) ってな具合に。
で、ポインタ型の仮引数precordで受けたら、今度はbar(precord)というようにアドレスを渡す。
そんなんで、偶に付け忘れるわけです。
アドレス演算はあまり使わないようにはしているけど、どうしても必要な場面はありますから。
0758447NGNG
>で、僕が728で言ったことは「静的な型付けのおかげで回避
>できるバグってどの程度のもの?」ということなんだけど、
>悪いけど、ここで述べたようなコーディング規約で回避でき
>る程度のバグだけなんじゃないの? って気がするわけ。
あ、いや、僕もまさにそう(ソースコードレベルでのバグチェック)
だと思うんですけど。ほんで総称もソースコードレベルでの多態に過ぎないと
思ってたわけです。
0759デフォルトの名無しさんNGNG
>>758
ソースコードレベルでの多態ってどういう意味?
0760デフォルトの名無しさんNGNG
http://hoge.s7.xrea.com/tiki/tiki.cgi?c=v&p=%B7%BF%A4%CA%A4%B7%B8%C0%B8%EC%C0%C2%A4%C3%A4%C6%A4%E8%A4%B7
このスレ面白かったんで、勝手に適当に議論の一部分だけWikiにまとめてみました。
気が向いた人がいたら修正、加筆してくれるとうれしいです。構成とかも、全然変えて良いんで。
0761デフォルトの名無しさんNGNG
>1-9あたりまでは完全な糞スレだったのに良く伸びたね。
途中から関数言語ユーザーが乱入してきて
理解不能になってしまったんだけど...

関数型言語の考え方理解するとC++/Javaな
手続き型・オブジェクト指向言語でのコーディングに
良い影響を与えることってあるのかな?
それがあるならやりたいなとは思うんだけど。
0762デフォルトの名無しさんNGNG
>>760
> 逆に、型あり言語は実行時にそのようなエラーが起きる可能性があります。
の部分は?
0763デフォルトの名無しさんNGNG
>>761
おれとってはよい影響はあったよ。高階関数とか、マクロ(Lisp)とか。
逆に C/C++/Java がじれったくなることもあるけどね。
0764デフォルトの名無しさんNGNG
>>762
まあ、そこは型無し言語は、の間違いだろうけど、
静的型付け言語でも実行時型チェックが必要な場合は
結構多いよね。
JavaでいうNarrowing Type Conversionとか。
0765デフォルトの名無しさんNGNG
>>763
同意。
宣言的プログラミングのスタイルと
高階関数とカリー化と遅延評価に触れたことで、
手続き型ベースのオブジェクト指向言語でも
考え方の幅を広げるのにとても役に立ったと思う。
■ このスレッドは過去ログ倉庫に格納されています