<   2009年 12月 ( 28 )   > この月の画像一覧

プログラム言語とプログラム

プログラム言語が変わっても、実際のプログラムの動作が同じなら、どのプログラム言語を使っても同じ事ではないかと思った。そこで、標準入力から一行読み込んで、それを表示するプログラムをいろいろな言語で書いてみた。

C言語 (stdio.c)

#include <stdio.h>

int main(void)
{
    char str[80];

    fgets(str,80,stdin);
    puts(str);

    return 0;
}

C# (stdio.cs)

using System;

class Example
{
  static void Main()
  {
    string str = Console.ReadLine();
    Console.WriteLine(str);
  }
}

Perl (stdio.pl)

$str = <STDIN>
print $str;

Ruby (stdio.rb)

str = gets.chomp
puts str

Haskell (stdio.hs)

main = do
  cs <- getLine
  putStrLn cs

Scheme (stdio.scm) : Guile

(begin
(define (read-line cs)
  (let ((ch (read-char)))
    (if (eqv? ch #\newline)
       (list->string (reverse cs))
       (read-line (cons ch cs)))))

(display (read-line '()))
(display #\newline))

同じ事をやるのなら、やはり余計な記号がなくて短い方がいいなとあらためて思った。

まだまだ、新しいプログラミング言語は出現するだろう。たくさんのプログラムが作られていく中で抽象化して部品化できるアルゴリズムが明確になってきたら、そのアルゴリズムを端的に表現できるプログラム言語が現れるに違いない。

一方で、速度的な問題や細かい調性をしなくてはならない問題については、C言語のような低レベルの言語の価値は残っていくだろう。

部品的なアルゴリズムについては簡潔な表記でプログラムでき、かつ、細かいハード寄りの動作や速度を要求されるプログラムについては、低レベルまで記述できる言語とのインターフェースを自動的に作ることができるようなプログラム言語が、未来の言語として望ましいのかもしれない。
[PR]
by tnomura9 | 2009-12-31 10:45 | 話のネタ | Comments(0)

C#の仕様

『C#によるプログラミング入門』のサンプルコードを入力して動作確認しながら読んでいたが、体力的に到底無理な感じがしたので、サンプルコードを実行せずに、C#の仕様を一通り読むだけ読んでみた。

読んでみて感じたのは、仕様の説明を過去にやったRubyのプログラム例に置き換えて読んでみると仕様の意味がよくわかるということだ。コンパイル、実行をしないので、細かい記法の注意点は頭に残らないが、その記法で何をやろうとしているのかは分かる。しかし、同じことをやるのに、Ruby の記法のほうが直感的に理解しやすかったような気がする。

一読した印象は、C#の現在の仕様は、Rubyで行っていることをC言語で行えるようにしたという感じだ。ただ、その後の機能拡張を見ていると、データベース処理や、関数型言語の特徴まで取り入れようとしているらしい。したがって、仕様は肥大化していっている。この傾向が良いものかどうかは分からない。

オブジェクト指向のプログラミングスタイルとイベント駆動型のプログラミングはGUIの発達とともに洗練されてきた。しかし、オブジェクト指向のプログラミングとイベント駆動型のプログラミングは同じGUIに使われているが、技術としては別のものだ。手続き型のプログラミングスタイルと、関数型のプログラミングスタイルも特徴はかなり違っている。データベース検索言語のそれも特異な位置づけを保っている。これらを包含する大きな言語が果たして可能なのだろうかと思われる。

Gtk-2.0 に見られるように、C言語を使っていても、オブジェクト指向的でイベント駆動的なツールキットを作ることができる。Gtk-2.0を使ってプログラミングしているときは、C言語で書いていても、関数と関数をつなぐ糊の役割を果たしているだけで、全く別の言語を使ってプログラミングしている気がする。

C言語の仕様が比較的小さく、IO処理やその他の処理をすべて関数やライブラリで実現するようにしたのは卓見だったような気がする。ライブラリの性質は時代とともに変化していったが、C言語の仕様はほとんど変化していない。

むしろ、言語の仕様よりも、ライブラリで何を実現しようとしているかの方が大切なのではないだろうか。言語の役割はそれらのライブラリを効率的につなぎ合わせることのような気がする。Gtk-2.0のように巧妙なライブラリがあれば、プログラミングはどの言語を使ってもそう変わらないものになる。

かといって、オブジェクト指向プログラムを記述するのには、RubyやC#を使った方がわかりやすいし、プログラム言語の記法の重要さは明白だ。

しかし、もっと大事なのは、RubyでもC#でも、もっというとC言語でも同じことをやっているというプログラミングの抽象性の方ではないだろうか。ループはどの言語でも同じことをやっているし、オブジェクトのメソッド呼び出しはRubyでもPythonでもPerl5でも同じことをやっている。実際のプログラミングの中に現れてくるこの、データの抽象性に注目していけば、より簡潔な記法で同じことを行えるプログラミング言語を発見できるかもしれない。

さらに、手続き型の言語と関数型の言語のように混在させると不都合なほど仕様が混乱する可能性もある。このような場合は、無理に統一的にひとつの言語で記述するというのではなく、データを介する両者のインターフェースの方法を工夫した方がいいのではないかと思う。SWIGなどを見ていると、スクリプト言語とC言語プログラムの自動的なインターフェースを作ることが、どんなに現場の人間にとってありがたいかが分かる。

まあ、いろいろな考え方はあるかもしれないが、C#がC言語を取り入れた上に、簡潔な記法でオブジェクト指向プログラムを作ることができるというのは事実だし、さらに、.NET Framework という強力なツールを使うために設計されているという事情を考えると、覚える労力を払う価値は十分あるのではないかと思う。
[PR]
by tnomura9 | 2009-12-30 21:45 | C# | Comments(0)

C# 練習プログラム

Ubuntu の Ubuntu ソフトウェアセンターからは Mono Documentation がインストールできる。C#のチュートリアルも充実しているが、いちいちエディターを立ち上げてコンパイルするのが面倒になってきたので、Ruby でC#のスニペットを動作させるプログラムを作ってみた。コマンドラインで ics で起動して ics> のプロンプトが出てきたら、e を入力すると Vi でプログラムが編集でき、b でコンパイルでき、r でプログラムを実行できる。ics を終了する時は、exit と入力する。

これだけのプログラムだが、結構快適にC#の勉強ができるようになった。

プログラム名:ics

#!/usr/bin/ruby
require "readline"
include Readline

def edit
  system "vi sandbox.cs"
end

def build
  system "csc sandbox.cs"
end

def run
  system "./sandbox.exe"
end

loop do
  begin
    line = readline("ics> ", true)
    case line
    when "e"
      edit
    when "b"
      build
    when "r"
      run
    when "exit"
      exit
    end
  rescue SyntaxError, LoadError, StandardError
    STDERR.puts "Warning: #$!"
  end
end
[PR]
by tnomura9 | 2009-12-30 12:19 | C# | Comments(0)

SWIG

自分で作ったC言語の関数をRubyで使えたら便利だが、拡張ライブラリを作るのは少々敷居が高い。しかし、SWIGというアプリケーションを使うと、C言語のヘッダーから自動的に拡張ライブラリを作ることができる。

Ubuntu で SWIG を利用するための準備としては、SWIGのインストールと、拡張ライブラリを作るためのRubyのヘッダファイルのインストールが必要だ。どちらも、Synaptic で行うことができる。swig パッケージと libruby-dev パッケージをインストールしておく。

次に使いたい関数をCで記述した example.c を作り、gcc -c example.c でオブジェクトファイル example.o を作る。

/* File : example.c */

/* Compute factorial of n */
int fact(int n) {
    if  (n <= 1) return 1;
    else return n * fact(n-1);
}

/* Compute n mod m */
int my_mod(int n, int m) {
    return(n % m);
}

次に、example.c のヘッダーファイルにSWIGのディレクティブを付け加えた example.i を作る。

/* File : example 1 */
%module example
%{
/* Put headers and other declarations here */
%}

extern int fact(int);
extern int my_mod(int n, int m);

このファイルを使って、swig -ruby example.i でラッパープログラムのファイル example_wrap.c を作る。さらに、gcc -c example_wrap.c -I/usr/lib/ruby/1.8/i486-linux でコンパイルしてオブジェクトファイル example_wrap.o をつくる。

最後に、gcc -shared -o example.so example.o example_wrap.o で shared library の example.so を作る。

この、example.so を require すると、Example モジュールの関数、fact() と my_mod() が使えるようになる。

$ irb
irb(main):001:0> require 'example.so'
=> true
irb(main):002:0> include Example
=> Object
irb(main):003:0> fact 5
=> 120
irb(main):004:0> my_mod 5,3
=> 2

これで、ユーザインターフェースはRubyで記述し、速度の必要な処理はC言語でプログラムするという使い勝手の良いプログラミングが誰にでもできるようになる。

C#にしても、SWIGにしても、だんだん共通に使う部品は単に組み合わせるだけで作れるようにして、本当に必要な部分だけをプログラミングできるという開発効率の高い手段が得られるようになってきている。

この傾向を見て分かるのは、プログラムを作るときに、ユーザーインターフェースのように、共通な部分がひどく多く、ユニークな部分は実は少ししかない場合が多いということだ。この、共通な部分の部品化がだんだん進んできたために、少ない労力でプログラムを作ることができるようになってきている。

これからは、プログラム言語のどれが優れているという議論ではなく、部品化されたモジュールを活用して、本当に必要な部分にだけ力を集中するにはどうしたら良いかという議論がなされていくのではないだろうか。

C#の良いところは、このような部品の利用と、低レベルのプログラミングがシームレスに行われるということだろう。これからC#が普及していくのかどうかは予測できないが、魅力のあるプログラミング言語だと思う。
[PR]
by tnomura9 | 2009-12-30 03:32 | Ruby | Comments(0)

Visual C# Express Edition と MonoDevelop

C#の概要を読んでいたら、基本的な構文が C とほとんど変わらないのがうれしかった。

しかし、文字列を収めるString 型や、多次元配列の型が追加されており、Cそのものよりはプログラミングが楽に感じられるだろうと思われた。また、クラスの作り方に余分な配慮がいらず、メソッドの呼び出しもRubyに似て . のあとにメソッド名を記述することで呼び出される。ライブラリの読み込みも using System のように名前空間を指定するだけで、特定のヘッダーファイルを指定する必要もない。おそらく、自分で記述したライブラリも名前を using で呼び出すだけなのだろう。

C#を使ってみたくなったので、Visual C# Express Edition をインストールしたが、Visual Basic 並の快適さで、GUIを組み立てることができた。とくに、慣れている C 言語の表記でプログラムを記述できるのがうれしい。

C#が気に入ったので、Linuxでも使えないかと探していたら、Mono というプロジェクトがあった。このサイトからダウンロードできる MonoDevelop を使うと、C#のコンパイラが手に入る。このページを読んでいたらUbuntuには公式のレポジトリがあり、Ubuntu ソフトウェアセンターからインストールできることがわかった。

インストール後、端末を起動し、Vi で次のファイル hello.cs を作った。C# は、C sharp と読むので、拡張子を .cs にする。

$ cat hello.cs
using System;
class Hello
{
  static void Main() {
    Console.WriteLine("hello, world\n");
  {
}

コンパイルは csc hello.cs とすると実行ファイルの hello.exe ができる。Linux で hello.exe は変な感じだがちゃんと動いた。

$ csc hello.cs
$ ls
hello.cs hello.exe
$ ./hello.exe
hello, world

MonoDevelop はアプリケーションメニュー・プログラミング・MonoDevelop を選択すると、統合型の開発環境を使うことができる。Visual C# のようにGUIでというわけには行かないが、開発が楽になるだろう。このC#コンパイラはC#で開発されており、170万行くらいになるそうだ。

C#の学習は、楽しいかもしれない。
[PR]
by tnomura9 | 2009-12-29 18:56 | C# | Comments(0)

.Net Framework

C#のチュートリアルを読んでいたら、このコンパイラが出力するのは機械語のプログラムではなく、.Net Framework 上で動く共通中間言語(CIL)だということがわかった。

C#で作られたプログラムはCILにコンパイルされ、それを、各種のOS上の .Net Framework が実行する。CILに適合していれば、VisualBasic でもC++でもC#でも、.Net Framework を使ったプログラムを作れるわけだ。

したがって、.Net Framework というツールキットのようなものを使うのなら、上のプログラム言語の何を使っても良いことになる。CでGTK+のプログラムを作成しても、Ruby/GTK2 で作成しても、速度の面を除いたら同じようなウィンドウを生成することができるようになるのと一緒だ。

こういう方式の利点は、

1. OSの種類が違っていても、.Net Framework が乗っていれば、コンパイルしたプログラムを使うことができる。
2. データベースのようなアプリケーションにも.Net インターフェースをつけると、C#から直接データベースを操作するプログラムを書くことができる。
3. メモリ管理などの面倒な操作を .Net Framework で肩代わりしてくれるのでプログラムが簡単になる。
4. ネットワークを介した分散処理や、並列処理を実行する機能が .Net Framework で提供されているので詳しい知識がなくてもそれらを使ったプログラムを作ることができる。

Java の機能と被っている気がする。WBでもC++でもC#でも同じものが作れるのなら、覚えることが少なそうなC#はいい選択かもしれない。

C#はオブジェクト指向言語だ。.Net Framework がそうなっているからというより、GUIのプログラムが普及する中でオブジェクト指向のプログラムが当たり前になった。Rubyでプログラムを作った経験があれば、C#は比較的容易に習得できるのではないだろうか。オブジェクト指向プログラムの勉強で一番苦労したのが、オブジェクトでプログラムをつくるということはどういう事かというイメージを持つことだ。

全くプログラムを作ったことのない人が独学でプログラミングを勉強する場合には、C言語またはRuby -> C言語またはRuby -> C++またはC#またはJava -> Javascript の順に勉強して言ったら効率がいいのではないだろうか。あるいは、コマンドラインで動く Javascript はあってもいい気がする。余裕があれば、Scheme も Haskell も知っていると便利だ。
[PR]
by tnomura9 | 2009-12-29 10:11 | C# | Comments(0)

Windows 7 搭載のノートパソコンを買った

ついに我慢ができなくなって、Windows 7 搭載のノートパソコンを買った。東芝の dynabook だ。

ウェブブラウザは、chrome をダウンロードして、Javascript コンソールも覗いてみた。冗談かと思えるくらいに変な変換をするMSIME に嫌気がさしていたので、日本語変換も google 日本語入力に変えた。これは、おすすめだ。近所の地名も一発で変換してくれる。

Windows のプログラミングにも興味が出てきたので、本の付録に付いてきた、Visual Studio Express Edition 2008 をインストールした。

生まれてはじめてVisual Basic を使ってみて、簡単にGUIが作れるのに驚いたが、コーディングの様式に違和感を感じた。Dim A as Integer などは生理的に受け付けない感じがして、諦めた。

C++もいろいろ悪い噂を聞いているので、勉強するのは気が重かった。

ところが、Visual Basic と Visual C++ のおまけのようにして、Visual C# が付いていたが、ネットで調べてみると意外に評判がいい。チュートリアルには初めてプログラミングを学ぶ人にも適していると書いてあった。使ってみたら、Visual Basic のように簡単にGUIが作れるし、コードも簡潔で綺麗だ。どうせ、仕事でプログラミングをする機会はないだろうから、せっかくなので、C#に挑戦してみることにした。

今度のパソコンは完全にプログラミング専用になりそうだ。

もちろん ActiveScriptRuby と Dr. Scheme と Haskell Platform もインストールした。
[PR]
by tnomura9 | 2009-12-28 01:15 | C# | Comments(0)

キー入力イベントを発信させる方法

キー入力イベントをRuby/Gtkでやらせようと思っていろいろとやってみたがうまくいかなかったので、Xlib 関係の記事を検索していたら、T. Sato さんのホームページで、xvkbd というソフトウェアキーボードが公開されていた。ソースもダウンロードできる。

XのKeySymの文字列を引数にして、キー入力イベントを発生させる fake_key のようなプログラムがあれば次のようなプログラムでもソフトウェアキーボードを動かすことができる。実用的にはC言語で書いたライブラリをRubyで使えるようにすることになるだろうが、かなりの勉強が必要だ。

fake_key の作り方はネットで教えていただいたが、キー入力イベントをプログラムで発生させると、自動的に fake タグがついて、rxvtなどでは無視するようになっているらしく、セキュリティに関連するようなので、このようなブログで公開するのは控えた。上に紹介したウエブを読めば、作れると思う。キー入力イベントの管理については、Windowsではそう厳しくないらしく、スクリーンキーボードのフリーソフトはたくさんあるので、調べれば出てくるかもしれない。

今度の試みで、少し Xlib や、Gtk+2.0 について調べてみたが、それほど恐れることはなく、順序良く勉強していけば独学でも理解できるようになるのではないかという希望が持ててきた。そのためには、まず、Ruby/Gtk2 を学んだほうが早そうだ。Ruby/Gtk2 なら、驚くほど簡単にGUIのプログラムを書くことができるし、これでプログラムを作った経験があれば、GTK+2.0 や Xlib の関数が何をやっているのかを理解することができる。これで休みの楽しみが一つ増えた。

#!/usr/bin/ruby

require 'gtk2'

class Button
  @@repeat = -1

  def initialize(id, label, chars)
    @id = id
    @label = label
    @chars = chars
    @n = chars.length
    @i = 0
    
    @button = Gtk::Button.new(label)
    @button.signal_connect("clicked") do
      if @@repeat == id
        system "fake_key BackSpace " + @chars[@i]
      else
        @i = 0
        system "fake_key " + @chars[@i]
      end
      @i = (@i + 1) % @n
      @@repeat = id
      STDOUT.flush
    end
  end
  attr_reader :button
end

window = Gtk::Window.new
window.signal_connect("delete_event") do
  Gtk.main_quit
end
window.keep_above = true
window.accept_focus = false

table = Gtk::Table.new(4, 4, true)
window.add(table)

button0 = Button.new(0," A J ", ['a','j'])
button1 = Button.new(1," T K ", ['t','k'])
button2 = Button.new(2," S Z ", ['s','z'])
button3 = Button.new(3," F V", ['f','v'])
button4 = Button.new(4," E X ", ['e','x'])
button5 = Button.new(5," M N ", ['m','n'])
button6 = Button.new(6," R L ", ['r','l'])
button7 = Button.new(7," - ' \" ", ['minus',"apostrope",'quotedbl'])
button8 = Button.new(8," I Y ", ['i','y'])
button9 = Button.new(9," H B ", ['h','b'])
button10 = Button.new(10," D G ", ['d','g'])
button11 = Button.new(11," , . ?", ['comma','period','question'])
button12 = Button.new(12," O P ", ['o','p'])
button13 = Button.new(13," U W ", ['u','w'])
button14 = Button.new(14," C Q ", ['c','q'])
button15 = Button.new(15,';:/\\', ['semicolon','colon','slash','backslash'])
button16 = Button.new(16," -> ", [''])
button17 = Button.new(17," BS ", ["BackSpace"])
button18 = Button.new(18,"Enter", ["Return"])
button19 = Button.new(19,"Space", ['space'])

table.attach_defaults(button0.button,0,1,0,1)
table.attach_defaults(button1.button,1,2,0,1)
table.attach_defaults(button2.button,2,3,0,1)
table.attach_defaults(button3.button,3,4,0,1)
table.attach_defaults(button4.button,0,1,1,2)
table.attach_defaults(button5.button,1,2,1,2)
table.attach_defaults(button6.button,2,3,1,2)
table.attach_defaults(button7.button,3,4,1,2)
table.attach_defaults(button8.button,0,1,2,3)
table.attach_defaults(button9.button,1,2,2,3)
table.attach_defaults(button10.button,2,3,2,3)
table.attach_defaults(button11.button,3,4,2,3)
table.attach_defaults(button12.button,0,1,3,4)
table.attach_defaults(button13.button,1,2,3,4)
table.attach_defaults(button14.button,2,3,3,4)
table.attach_defaults(button15.button,3,4,3,4)
table.attach_defaults(button16.button,0,1,4,5)
table.attach_defaults(button17.button,1,2,4,5)
table.attach_defaults(button18.button,2,3,4,5)
table.attach_defaults(button19.button,3,4,4,5)

window.show_all

Gtk.main
[PR]
by tnomura9 | 2009-12-27 10:27 | NetWalker | Comments(0)

Ruby/Gtk2 でウィンドウを最前面に貼り付ける

Ruby/Gtk2 でウィンドウを最前面に貼り付ける方法が分かった。張り付けたいウィンドウウィジェットの keep_above 属性を true にすれば良いだけだった。

window.keep_above = true

ついでに、ウィンドウにフォーカスさせなくする方法は、

window.accept_focus = false

ウィンドウマネージャーのリソースで管理するのではなかったのだ。忘れないうちにメモした。前回の記事のプログラムに、上の二行を加えたら想定していた動作をしてくれたが、gedit をフォーカスにしてボタンをクリックしたが、key-press-event が伝わっていかなかった。

しかし、ハードルは後一個だけになった。どうやって、イベントをXサーバーに渡すかということだ。
[PR]
by tnomura9 | 2009-12-20 22:59 | NetWalker | Comments(0)

signal_emit

昨日と今日の二日を潰して、ボタンからキー入力イベントをソフトウェア的に発生させる事ができた。忘れてしまうのはもったいないので下にプログラムを掲載した。

ソフトウェア・キーボード実現のハードルとしては、このイベントをXサーバーを介して他のフォーカスされたウィンドウに渡すことができるかということ。キーボードをフォーカスさせないようにすることと、stay on top で最前面に張り付けることが必要だが、それはGTK+の仕事ではなくて、ウィンドウマネージャーの仕事らしい。

GNOMEのホームページをざっと眺めたが関連の記事を見つけ出せなかった。ソフトウェアキーボードのアプリは既にあるのだから、ソースを取り寄せて調べれば良いのだろうけれどそこまでの知識と時間がない。Ruby/Gtk2 のチュートリアルか何かでイベントを他のアプリケーションに送る方法を取り扱ってもらえるといいのだが。

これ以上は先へ進めそうにないので、ひとまずソフトウェアキーボードの記事はこれで終わる。カスタマイズが簡単なRuby/Gtk2 のソフトウェアーキーボードのソフトが出現するのをじっと待つことにする。

イベントを他のアプリケーションに送りたいなどという贅沢を言わなければ、Ruby/Gtk+2でのプログラム作りはとても楽だった。GUIプログラミングへの気持ちの壁がかなり低くなったような気がする。部品は最初から豊富に揃っているし、イベントに応じてコールバック関数を数行書くだけで、それらしい動作をしてくれる。Ruby の手軽さも手伝って、お気楽GUIプログラミングを楽しめた。これで、また楽しみがひとつ増えた気がする。

require 'gtk2'

event = Gdk::EventKey.new(Gdk::Event::KEY_PRESS)
event.set_keyval(?a)

window = Gtk::Window.new
window.signal_connect('destroy') {
  Gtk.main_quit
}

window.signal_connect('key-press-event'){|w,e|
  print e.keyval, ': ', e.keyval.chr, "\n"
  false
}

button = Gtk::Button.new("key-press-event")
button.signal_connect("clicked") {
  puts "clicked"
  window.signal_emit('key-press-event', event)
  false
}

window.add(button)
window.show_all
Gtk.main
[PR]
by tnomura9 | 2009-12-20 17:45 | NetWalker | Comments(0)