てきとう

てきとう

1からやり直し:hello, world編

基本

with Ada.Text_Io;
procedure Hello is
begin
   Ada.Text_Io.Put_Line("hello, world");
end Hello;

応用:use

with Ada.Text_Io;
use Ada.Text_Io;
procedure Hello is
begin
   Put_Line("hello, world");
end Hello;

応用:renames

with Ada.Text_Io;
procedure Hello is
   package TIO renames Ada.Text_Io;
begin
   TIO.Put_Line("hello, world");
end Hello;

宣言時にrenamesを使うと別名として宣言できます。
パッケージに短く適当な別名をつけることで、書く際の負担を減らしつつ可読性を上げることができます。

【テスト】Mountain LionでGCCを--enable-languages=adaでビルドしてみた記憶【コピペ】

*1

お久しぶりですが別に何もありません。いつも通りのダメ人間です。
適当にやってもできなかったけど適当に調べたらできたので記録というか記憶をメモ。
記憶なので細かいところ違うかと。

用意するもの

  • 動くGNAT。今回はgnuadaの4.6.0を使用。
  • gccのソース。今回は4.7.1。
  • gccのビルドに必要らしいGMPとかMPFRとかMPCとか。細かくは忘れたのでドキュメント参照してください。
    • MacportsだのFinkだのHomebrewだのをお勧めします。

手順

ここここを参考にやりましたので、そちらを見ることをお勧めします。
まとめると、要点はconfigureに以下をくっつけること。

CC='gcc -D_FORTIFY_SOURCE=0'

というわけでconfigureだけ気をつければいいので、gnuadaのGNATにパス通して

$ ./configure CC='gcc -D_FORTIFY_SOURCE=0' \
--enable-languages=c,c++,ada \
--prefix=$SOMEWHERE \
--build=x86_64-apple-darwin12
(略)
$ make
(略)
$ make install
(略)

こんな感じで動いてそうなGNATができました。


ちなみにCC=...を忘れるとldが「x86_64でこのシンボル知らねーよ!」とだかよく分からない暴言を吐いてconfigureに失敗します。
そのうち直ることを期待しときましょう。

*1:先程はてダに書いたもののコピペです。

ダイナミックディスパッチを捨てる方法(おまけ)

Adaだとどうするん?と思って適当にそれっぽいコードを書いたところ、普通にキャストすれば良さそうな感じ。*1

with Ada.Text_Io;
procedure Dsp_Test is

   package Bs is
      type B is tagged null record;
      procedure Method(Obj: in out B);
   end Bs;
   package body Bs is
      procedure Method(Obj: in out B) is
      begin
         Ada.Text_Io.Put_Line("B#method");
      end Method;
   end Bs;

   package Ds is
      type D is new Bs.B with null record;
      procedure Method(Obj: in out D);
   end Ds;
   package body Ds is
      procedure Method(Obj: in out D) is
      begin
         Ada.Text_Io.Put_Line("D#method");
      end Method;
   end Ds;

   B:Bs.B'Class:=Ds.D'(Bs.B with null record);

begin
   B.Method;       --> D#method
   Bs.B(B).Method; --> B#method
end Dsp_Test;

ドット記法使うと凄くOOPLっぽく見えますね…
ちなみに95方式で

   Method(B);
   Method(Bs.B(B));

と書くと、Methodが見えないのでコンパイラに怒られますが、"use Bs, Ds;"しておけばドット記法を使った時と同様に解決してくれるようです。(この例では。)

*1:面倒くさくてARM確認してませんので規格的に正しいかは不明。

ダイナミックディスパッチを捨てる方法

Java弄っててふと疑問に思ったのでググった結果をメモ。
Java でメソッドを静的にディスパッチする - odz buffer
Java でインスタンスメソッドを静的にコールする方法はない? 2 - Smalltalkのtは小文字です
とりあえず普通に使ってる分には無理、という理解で良いのかな。
private限定じゃあんまり意味ないし…

Gem #3

http://www.adacore.com/2007/05/28/gem-3/

「limited typeを返すような関数が書けるよ!」

#1と#2から、limited typeにも代入できるようになったので関数が使えるようになりました。
中身の説明が興味深い。

In this case, Rumplestiltskin_Is_My_Name is allocated in the usual way (on the stack, presuming it is declared local to some subprogram). Its address is passed as an extra implicit parameter to Make_Rumplestiltskin, which then passes that same address on to Make_T, which then builds the aggregate in place at that address.

http://www.adacore.com/2007/05/28/gem-3/

適当訳: *1

この例では、 Rumplestiltskin_Is_My_Name は(サブプログラム内に宣言されていると仮定しているのでスタック上に)通常通り配置されます。そのアドレスはMake_Rumplestiltskin に暗黙のうちに追加の引数として渡され、その後同じアドレスが同様に Make_T に渡され、その後 Make_T は渡されたアドレスの指す先に aggregate を配置します。

アドレスを一々関数に渡すことで「limitedはコピーされない」ことを実現しているらしい…苦労してるんだなぁ…


この新しい機能を使えば似非単一代入で似非関数型言語っぽいことができます…?
こんな感じになる?:

type T is limited record
   N:Integer;
end record;
function Make_T(N:Integer) return T is
begin
   return (N=> N);
end Make_T;
function F(X:T) return T is
begin
   return (X.N+1);
end F;
function G(X:T) return T is
begin
   return ((F(X).N)*(F(X).N));
end G;
V: T := F(Make_T(1));
V2: T := G(V);

…うん、やらなくていいや。*2


Ada2012のExpression Functionsを使えば…!

type T is limited record
   N:Integer;
end record;
function Make_T(N:Integer) return T is (N=> N);
function F(X:T) return T is (X.N+1);
function G(X:T) return T is ((F(X).N)*(F(X).N));
V: T := F(Make_T(1));
V2: T := G(V);

わりとマシ…わりと…

*1:「配置」が気持ち悪いけど語彙が貧弱で他に思いつかない上、 aggregate は「集合」にするのが気持ち悪すぎるので放置

*2:というか試してないけどコンパイル通るんだろうか