- PR -

特集「私がJavaからC#に乗り換えた10の理由」について

投稿者投稿内容
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2003-07-15 17:34
>Jitta さん

最後まで「設定も取得も素通り」の状態であれば良いのですが、途中で変更があった場合のことを考えてフィールドに直接アクセスさせないわけです。
たとえば、「Nameは長さ最大20文字までに変更」となった場合に、フィールドに直接アクセスさせている場合はどうしようもありません。
アクセスする側のオブジェクトで20文字というのを気にしながらアクセスしなければならないことになります。これはC言語で配列にアクセスするときに、配列の長さをアクセスする側が気にしながらプログラミングしたいたことと同じでバグが含まれやすくなります。

後々の変更を考えて素通りでもプロパティ使うということではないでしょうか。

>Kuolema さん
>この会議、一体いつ終焉を迎えることやら・・・
>皆様は、議論すべきネタは尽きたのでしょうか

もう、言うことは言ったんじゃないですか。
「記事の内容はおかしい」かどうかという話についても、もう出尽くしたでしょう。
言語やオブジェクト指向について見つめなおすきっかけになったでしょうし、結構有意義だったと思いますよ、私は。
未記入
大ベテラン
会議室デビュー日: 2003/06/28
投稿数: 219
投稿日時: 2003-07-15 19:48
Ken@半身Macユーザーです。
まず、不適切な発言があったことをお詫びします。
えっと、自分としては、手元に変わった環境があるので (^^;
各OSのCLI実装がどこまでできるのか確認して、結果がわかりましたらどこかで
公表したいと考えてます。(そんなもんどこで使うんだよ、という
ツッコミはありです。が、使えるに越したことはないかと。
Win APIコールは当然無理としてマルチバイトキャラクタがきちんと
扱えるかどうか、とかちと心配・・・。

引用:

Jittaさんの書き込み (2003-07-15 13:52) より:

 で、相手が例えば嫁はんだと、Friendで宣言してあると・・・




このアクセス指定子応用範囲が広そうでいいですね。
ゆーしー
会議室デビュー日: 2003/07/15
投稿数: 1
投稿日時: 2003-07-15 20:34
はじめまして、ゆーしーといいます。
普段C++をほどほどに使っています。javaかC#には興味がありますが使っていません。
ですので興味深く、このスレッドを見させていただいています。

見ている中で少し疑問を持ったことがあるので質問したいと思います。
たぶん勘違いしていることが多いと思いますが、あたたかいツッコミを頂けるとうれしいです。

・オブジェクト指向言語でもクラス志向(静的型付け言語)とオブジェクト(インスタンス?)志向(動的型付け言語)があると思います。その2つの志向を持つ言語で同じ仕様からプログラムを作った場合、プログラムの構造にどういう差が現れるのでしょか?それとも現れないのでしょうか?
・・ちなみに、この質問する原因は、C++を使っている限り古典的オブジェクト志向(動的型付け)な設計と合わない設計になってしまうことが多いからです。

・多くの方がC#は、コンポーネント志向を持っている言語だといっておりますがコンポーネントってなんでしょうか?私の調べた限りでは、再利用可能な(他で流用できる)自己完結しているオブジェクト群という程度です。ですのでフレームワークより粒度が小さいものという程度しかわかりません。実際のところコンポーネントとは、どのようなものなのでしょうか?
(この部分は削除しました。eventとdelegateは、別のものでした。)

・最後に大雑把な質問になりますが、C#の特色とはなんでしょうか?良し悪しは、とりあえず横に置いといて、他のオブジェクト指向言語と、どのような差があるのか?とい点に私は興味があります。自分で使ってみて感じるのも良いでしょうが、既にC#を使っている人に、率直に感じていることを聞いてみたいです。

このスレッドに参加されている皆様、ぜひともご教授ください。
よろしくお願いします。

[ メッセージ編集済み 編集者: ゆーしー 編集日時 2003-07-16 07:43 ]
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2003-07-15 20:55
>たとえば、「Nameは長さ最大20文字までに変更」となった場合に、フィールドに
>直接アクセスさせている場合はどうしようもありません。
こういう変更は仕様変更になります.
呼び出される側だけでなく,呼び出し側のコードも変更する必要が出てきます.
#DLL地獄の本質はこれらしい.勝手に仕様を変えちゃいけません.

>アクセスする側のオブジェクトで20文字というのを気にしながらアクセスしなければ
>ならないことになります。これはC言語で配列にアクセスするときに、配列の長さを
>アクセスする側が気にしながらプログラミングしたいたことと同じでバグが含まれ
>やすくなります。
とすると,Nameを直接返したらいけないのでは?
#C#の文字列がJavaの文字列と根本的に異なるのでない限り.
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2003-07-15 21:09
こんばんは、meiです。

個人的にプロパティはget/setを便利にした程度と思っていたのですが、
皆さんの意見を見ていると、もうちょっと意味が深そうなので、
少し考えてみました。

例えばクラスに名前という属性がありましたとします。
get/set関数を用意すると、

person.getName();
person.setName(name);

となり、プロパティだと

person.Name;

とかになりますね。

ところで、名前という属性は関数でアクセスするものなのか、それとも値なのでしょうか?

機能的には関数でもプロパティでも同様の事が実現出来ますが、意味として考えると名前は関数ではなく値ですので、プロパティの方がより自然だと思います。

では、この機能が必須かと言われると微妙です。C++にプロパティを追加するのはどうか?と言われれば、不要な気がします。

理由の1つとして、
C++は言語として十分な歴史を持ってしまっているので、今までget/setでやってきたのを今更プロパティに置き換える気にならない、というのがあります。

2つ目として、
C++ではシンタックスシュガーにしかならないというのがあります。
ご存じの通り、C++は実行時型情報(リフレクション)が非常に弱いので、プロパティとして宣言しても、実行時にその情報を活用することが出来ない(get/setと変わらない)点です。

javaの場合はどうでしょうか?
javaもC#に比べれば歴史があり、今更という感じがあります。
ここはC++と一緒です。
しかし、javaの場合、強力なリフレクションを持っているので、プロパティという情報を活用できる可能性が見えます。なので、C++よりはプロパティに意味がありそうです。

じゃ、javaでプロパティを採用すべきなのかと言えば、そうではなく、
実行時の型情報は確かに必要かもしれないが、シンタックスシュガーはいらないし(Javaの思想にあわない)、
また、Javaの次のバージョンでカスタム属性がサポートされるようなので、例えば、カスタム属性でプロパティという意味を持たせてやれば、わざわざプロパティという要素を追加する必要はないとか思います。

一方、C#では便利なモノはどんよくに取り込む思想のようで、プロパティ(カスタム属性+シンタックスシュガーのようなもの)を持っています。


ここまででは、私はC#のプロパティが必要ないように思っていそうですが、そうではありません。機能面だけを考えるとわざわざプロパティなんて持ち込む必要がないと考えてしまいますが、その意味まで考えるとどうでしょうか?


C++あがりなので、C++を例にちょっと説明させて貰います。

C++にはclass(クラス)とstruct(構造体)がありましたが、デフォルトがpublicかprivateかの違いだけで、機能的な違いはありませんでした。

class A {
public:
void foo();
};

と、

struct A {
void foo();
};

は、全く等価です。
機能だけ見ると、classというキーワードなど、全く不要です。
しかし、classからクラスとしての意味を見いだせることが重要だと思います。
同等の機能があっても、意味が違えば分けるべきだと思います。


ちょっと脱線方向ですが、
私がCしか知らない人にC++のクラスを説明したときのことです。
オブジェクト指向の概念をいきなり説明するもちょっとだったので、
ファイル≒クラス
static関数≒プライベート関数
関数≒パブリック関数
みたいなことを言い、クラスは論理的な(Cで言うところの)ファイルだ、とか言いました。

もしくは、クラスを構造体に関数ポインタを持たせたようなモノなんて説明も、出来るかも知れません。

ここを見ている方々は、クビをかしげたり、つっこみを入れたくなるでしょう(笑)。
#私もオブジェクト指向を誤解させそうな説明で大失敗と思います(汗)。

構造体+関数ポインタ=クラスというのには同意出来ません。
クラスにはクラスの概念が存在し、似たようなことが実現出来ても、
それは決してクラスじゃありません。

派とかいう言葉は嫌いなんですが、便宜上C#派とJava派とに分けると、
classというキーワードが必要ということは、両派とも意見が一致していると思います。

クラス以外にも目を向けると、
ここで散々議論になった、イベントやプロパティはどうでしょうか?
私の立場をはっきりさせておくと、最初に少し述べたように、これらは必要(存在するのが理想)だと思っています。

例えばプロパティは"値"であり、get/set関数でアクセスされるものとは異なると思ってます。

その一方で、C++にプロパティはいらないとも思っています。

矛盾していますでしょうか?

そうではないです。
例えば、統一性のあることは良いことだ!と言えば、大抵の人は同意してくれると思います。

ですが、値型はやめて全て参照型に統一すべきだ、全ての型はObjectから派生する方が美しい!

と、いうとどうでしょうか?
「理想はそうかも知れないけど、パフォーマンスを考えると・・・」
とか、返されるでしょう。
この他にも理論上の美しさより優先されることがあるでしょう。

Javaの場合は、シンプルに優先度があり、
C#の場合は、便利さに優先度があります。
C++は速度でしょう。
#むちゃくちゃ乱暴で済みません。

機能とか表記法は似ているので、同じ価値観を持っていると錯覚しそうになりますが、
JavaとC#はかなり別物です。

お互いに非難しあうのではなく、
根本に流れる思想をみてどっちが自分に相応しいかが大切だと思います。


話の落としどころが分からなくなってしまったので、この辺で(汗)。
なんか、むちゃくちゃ長かったわりには、
つまらない結論で申し訳ないのです・・・


[ メッセージ編集済み 編集者: mei 編集日時 2003-07-15 21:21 ]

[ メッセージ編集済み 編集者: mei 編集日時 2003-07-15 21:24 ]
英-Ran
ベテラン
会議室デビュー日: 2002/06/12
投稿数: 55
投稿日時: 2003-07-15 22:32
引用:

コンストラクタの定義がソースにないっていうのは確かにそうですが、それいったら「すべてのクラスはオブジェクトから継承する」とかだって書いてません。class定義の「ルール」があるようにdelegate定義の「ルール」があるってことだと思えば。



回答その一:C#からオブジェクト指向を取り除くことはできませんが、delegateを取り除くことは難しくもなんともありません。重要度のまったく違うものをいっしょにしてはいけません。
回答その二:同等の機能を持ち、同等の記述で可能ならば、既存の概念では理解できないルールが加わるのと加わらないのとではどちらがいいかは明らかでしょう。

引用:

これだと「どの型のインスタンスが生成されたの?」になってしまうような。いや、正確にはメソッド自体が型であって、new target.handlerに修正してこれは型をインスタンス化しているのだ、と考えれば良いと思いますが、それだと例えばtest1 classのインスタンスのメソッド
public void test1method(object sender, EventArgs e){...}

test2 classのインスタンスのメソッド
public void test2method(object sender, EventArgs e){...}
の型は同じなのか違うのか。



明らかに同じ型(Method(void, object sender, EventArgs e)型のオブジェクト)です。

# 以前の例では戻り値の型指定を忘れてました。すんません。

「Hoge test1」と「Hoge test2」が同じ型なのと同様です(JavaScriptのFunctionオブジェクトが受け入れられるなら別に不思議なものではないはずですが……)。

引用:

まぁとりあえず、現状のように型を定義してそのインスタンスを作ってそれを(イベントに)登録する、といったほうが型システムにおいて自然だろうな、とは思います。



残念ながらC#のdelegateは、yaさんの言うようなものではないのです(引数として与えるtarget.handlerが何者なのかを考えてみてください)。yaさんの説明を額面通り受け取るならば私の提示した方式の方が自然になってしまう。

[ メッセージ編集済み 編集者: 英-Ran 編集日時 2003-07-15 22:33 ]
ya
大ベテラン
会議室デビュー日: 2002/05/03
投稿数: 212
投稿日時: 2003-07-16 02:34
引用:

明らかに同じ型(Method(void, object sender, EventArgs e)型のオブジェクト)です。




そうなら型付けが弱いと思います。

コード:
public delegate void SampleEvent1Handler(object sender, EventArgs e);
public delegate void SampleEvent2Handler(object sender, EventArgs e);

public class Class1
{
 public event SampleEvent1Handler SampleEvent1;
 ...
}

public class Class2
{
 public event SampleEvent2Handler SampleEvent2;
 ...
}

public class MainClass
{
 private void listenClass1SampleEvent1(object sender, EventArgs e)
 {
  Class1 c1 = (Class1)sender;
  c1......  
 }

 private void listenClass2SampleEvent2(object sender, EventArgs e)
 {
  Class2 c2 = (Class2)sender;
  c2....
 }
 private static void Main(string[] args)
 {
  Class1 c1 = new Class1();
  Class2 c2 = new Class2();
  MainClass m = new MainClass();
  //error : c1.SampleEvent1 += new SampleEvent2Handler(m.listenClass1SampleEvent1);
  c1.SampleEvent1 += new SampleEvent1Handler(m.listenClass1SampleEvent1);
  //error : c2.SampleEvent2 += new SampleEvent1Handler(m.listenClass2SampleEvent2);
  c2.SampleEvent2 += new SampleEvent2Handler(m.listenClass2SampleEvent2);
  ...
 }
}



これは極端な例なのですが…。
イベントを定義するのはカプセル化されたあるクラスなので、ほかのクラスとは独立性が高くあるべきです。
例え戻り値とパラメータが一緒でも、それは「偶然一致」したに過ぎない可能性があります。つまり、型付けはこの例の場合Class1とClass2の設計者が利用者に強制させるべきであり、それの意思表明がSampleEvent1Handler型やらということになります(Class1とClass2はそれこそお互いのことなんて知ったこっちゃないし別のdelegateとして扱ってほしい)。ただ、偶然一致しちゃってもまったくかまわない場合も多いし、登録する段階でそのインスタンスの型(senderとなるべきもの)は利用者はわかっているので、EventHanlder型をそのままつかっちゃうことも多いからあまり有効性がないのかも知れません(イベントの定義で強要する程度でOKとか)が、イベントに登録されるものを名前のある型として定義できるところ(つまりクラス設計者に完全に一任されている)が重要ではないかと思います。


引用:

残念ながらC#のdelegateは、yaさんの言うようなものではないのです(引数として与えるtarget.handlerが何者なのかを考えてみてください)。yaさんの説明を額面通り受け取るならば私の提示した方式の方が自然になってしまう。




なんか伝わってないかも。delegateの場合、delegateオブジェクトという新しい「オブジェクト」を作ってそれを相手先に登録するんです。既にクラスとともに実体化されたtarget.handlerメソッドオブジェクトそのものを登録するんではないんです。そのdelegateオブジェクトはアクセス権を部分的に越えられるにもかかわらずカプセル化をこわさないのです(上の例でlistenClass1SampleEvent1メソッドがprivateでも外部から発火したイベントから呼ばれます)。delegateオブジェクトという(メソッドオブジェクトに関連付けられているとはいえ)まったく別のオブジェクトだから足したり引いたりもできるんです。


自分でよんでみてもよくわからないところがある(w。この辺、私も体系的に説明できるようにしっかり理解したいので突っ込みお願いします。
いのつち
ベテラン
会議室デビュー日: 2002/05/14
投稿数: 73
投稿日時: 2003-07-16 10:33

いまいさん。Javaの手法を教えていただき、ありがとうございます。

javaとC# 似て異なるものですね。
java はフィールド・メソッド・クラス・インターフェイスこれらの
中でのみ、実装するという大前提の制約を設けた中で、
先人たちは駆使して手法を生み出してきたものだと実感します。
過去の資産も既に膨大なものとなっているので、一長一短には
変更できないでしょうし、またすべきでもないでしょう。

C#ユーザがjavaを学ぼうとしたとき、気をつけなければならない点が
いくつもあるような気がします。逆もありそうですが。

私自身は、この会議室での議論の中で、そういった注意すべき点が
見出せたらよいなと思って拝見させて頂いております。

そこで、悪夢を統べるものさんの意見はちょっと気になりました。

>>アクセスする側のオブジェクトで20文字というのを気にしながらアクセスしなければ
>>ならないことになります。これはC言語で配列にアクセスするときに、配列の長さを
>>アクセスする側が気にしながらプログラミングしたいたことと同じでバグが含まれ
>>やすくなります。
>とすると,Nameを直接返したらいけないのでは?
>#C#の文字列がJavaの文字列と根本的に異なるのでない限り.

悪夢を統べるものさんは否定以上の説明がないので、何を反論されているのか推測する
しかないのですがjava と C#は文字列の扱いが異なるのでしょうか.
コード:
public class Test
{
	private string x;

	public Test()
	{
		x = "ABC";
	}
		
	public string ST {get{ return x; } set{x = value;}}

	public static void Main(string[] args)
	{
		Test c = new Test();
		string p = c.ST;
		p = "HOGE";
		System.Console.WriteLine("P={0},c.ST={1},x={2}",p,c.ST,c.x);
	}
}


C#のソースですが、
この場合、結果は、P=HOGE,c.ST=ABC,x=ABC となります。
私はjava の場合 P=HOGE,c.ST=HOGE,x=HOGE になってしまうのかと
推測してしまいました。

もしそうならば、
>とすると,Nameを直接返したらいけないのでは?

というのはまさにそのとおり!なのですが。
C#の観点からすると、その前のサンプルコードや一郎さんの説明には、何の問題もないので、
javaの場合・・が気になります。

すごい勘違いをしているのかな? >私自身

スキルアップ/キャリアアップ(JOB@IT)