Raku で文字列を反転させる時に多分考えること

"Twitter" という文字列を反転させたいからと .reverse メソッドを呼ぶと:

say "Twitter".reverse;

以下のようにかっこで囲まれた何かが返ってくる。

(Twitter)

これは .reverse メソッドが配列用のメソッドであり、スカラーに対して呼び出すと要素が 1 つの配列として認識されてしまい、 配列が返ってくるからだ。

.^name を呼ぶと戻り値の型の名前を表示することができる。

say "Twitter".reverse.^name;

すると、Seq と表示された。

Seq

1 文字ずつに分割して(.split(""))、結合すれば(.join)、

Twitter".split("").reverse.join;

目的の値を得ることができる:

rettiwT

のだが、幸い Str クラスには .flip というそのズバリのメソッドがある。

say "Twitter".lc.flip.tc;
Rettiwt

他人が書いたコードを読んでいる時に 10 億回くらい思うこと

他人が書いたコードを読んでいる時に 10 億回くらい思うことを書いておこうと思う。

using してるのに finallyDispose() したり Close() しちゃう

何もわからないのだが、よく using で囲っているのにその中の try ... finally 文の finally 節で Dispose() したり Close() してしまっているコードを見る。

以下はとても典型的なコードで、もう一つ問題があるのだが、これは次で解説する。

dim result = new DataTable()
using reader = command.ExecuteReader()
    try
        result.Load( reader )
    finally
        reader.Dispose()
    end try
end using
return result

ここで、reader は明らかに IDisposable を実装しているのですごく単純に考えると end using のところで自動的に Dispose() されるので、finallyreader.Dispose() は必要ない。

多分、このコードを書くような人は、古 Java 話者の人か古 Java を少し話せる人で、using をただのおまじないか何かと思っているのだろう。

私が書き直すなら以下のようになる:

dim result = new DataTable()
using reader = command.ExecuteReader()
    try
        result.Load( reader )
    catch ex as Exception
        Trace.TraceError( ex.ToString() )
    end try
end using
return result

finally の替わりに catch 節にして、例外を出力ウィンドウに出力するようにした。

スコープ引き伸ばし症

先程書き直したコードだが、まだ改善するべき箇所がある。
それは result の宣言を using スコープの外に出している点である。

dim result = new DataTable()
using reader = command.ExecuteReader()
    try
        result.Load( reader )
    catch ex as Exception
        Trace.TraceError( ex.ToString() )
    end try
end using
return result

スコープの範囲を最小限にする原則からすれば、result の宣言は try 節の中で良いし、resultreturn するところも try 節の中でいい。
そのことを踏まえて書き直すと以下のようになる:

using reader = command.ExecuteReader()
    try
        dim result = new DataTable()
        result.Load( reader )
        return result
    catch ex as Exception
        Trace.TraceError( ex.ToString() )
    end try
end using

WSL2 の Debian を 10(buster) から 11(bullseye) にアップグレードした

/etc/apt/sources.listbusterbullseye に変更する。

deb http://deb.debian.org/debian buster main
deb http://deb.debian.org/debian buster-updates main
deb http://security.debian.org/debian-security/ buster/updates main
deb http://ftp.debian.org/debian buster-backports main

これが

deb http://deb.debian.org/debian bullseye main
deb http://deb.debian.org/debian bullseye-updates main
deb http://security.debian.org/debian-security/ bullseye/updates main
deb http://ftp.debian.org/debian bullseye-backports main

こうなる。

3 行目が無いらしく、ここをコメントアウトした。

次に

% sudo apt update

する。 ここで何かしらエラーが出たりする。

この後、

% sudo apt upgrade

を行うとパッケージを更新してくれる。 その後に

% sudo apt full-upgrade

とやると完全にアップグレードできるらしい。

うまくいった。

VB で 1 行ラムダ式を書きたい時

定義するとき:

dim succ = function(x) x + 1

使うとき:

Console.WriteLine( succ( 23 ) )

こういうような匿名型の配列を Dictionary にするには:

dim products = {
    new with { .Name = "オレンジ", .Price = 100 },
    new with { .Name = "リンゴ"  , .Price = 120 }
}

こういう風に書ける:

dim productMap = products.ToDictionary( function(product) product.Name, function(product) product.Price )

参考

方法: ラムダ式を作成する - Visual Basic | Microsoft Docs

VB10 の 匿名型配列: かるあ のメモ

VB 書いてるときに任意の型の Type 型を取得するいくつかの方法

VB に触れるのは久しぶりなので、右と左はおろか箸を持つ方の手がどっちなのか全然わからない。
C# においてこういう風に書いていたコードも:

aTable.Columns.Add( new DataColumn {
    DataType = typeof(string),
    ColumnName = "Name"
} );

VB ではどう書けばいいのかわからない(with を使うらしい…)。

C# における typeof(string)VB においては GetType(String) らしい。
先程の例は以下のように書ける:

aTable.Columns.Add( new DataColumn with {
    .DataType = GetType(String),
    .ColumnName = "Name"
} )

いくつかの方法なのに、1 つしか書いてないけどまあいいか。

参照

VB の char 型リテラル

VB ではシングルクォーテーションがコメントなので、char 型のリテラルはどうなるんだろうなーと思っていたら、 文字列っぽいリテラルの後に c をつけるらしい。

例:

"foo,bar".Split( ","c )

こういう例であれば、.ToCharArray() にしても大丈夫:

"foo,bar".Split( ",".ToCharArray() )

参照

Msys2 で Guile をビルドする時にビルドする人がしなければいけないこと

ビルドする際、以下のようなコンパイルエラーが出る::

  net_db.c: In function 'scm_gethost':
  net_db.c:144:18: error: storage size of 'inad' isn't known
  144 |   struct in_addr inad;
      |                  ^~~~
  net_db.c:174:21: warning: implicit declaration of function 'htonl' [-Wimplicit-function-declaration]
  174 |       inad.s_addr = htonl (scm_to_ulong (host));
      |                     ^~~~~
  net_db.c:185:15: error: invalid application of 'sizeof' to incomplete type 'struct in_addr'
  185 |   if (sizeof (struct in_addr) != entry->h_length)
      |               ^~~~~~
  net_db.c:193:14: error: dereferencing pointer to incomplete type 'struct in_addr'
  193 |       inad = *(struct in_addr *) argv[i];
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  net_db.c:194:39: warning: implicit declaration of function 'ntohl' [-Wimplicit-function-declaration]
  194 |       lst = scm_cons (scm_from_ulong (ntohl (inad.s_addr)), lst);
      |                                       ^~~~~
  net_db.c:144:18: warning: unused variable 'inad' [-Wunused-variable]
  144 |   struct in_addr inad;
      |                  ^~~~
  In file included from net_db.c:60:
  net_db.c: In function 'scm_return_entry':
  net_db.c:325:53: warning: implicit declaration of function 'ntohs' [-Wimplicit-function-declaration]
  325 |   SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_uint16 (ntohs (entry->s_port)));
      |                                                     ^~~~~
  vectors.h:72:73: note: in definition of macro 'SCM_SIMPLE_VECTOR_SET'
  72 | #define SCM_SIMPLE_VECTOR_SET(x,idx,val) ((SCM_I_VECTOR_WELTS(x))[idx]=(val))
     |                                                                         ^~~
  net_db.c: In function 'scm_getserv':
  net_db.c:374:30: warning: implicit declaration of function 'htons' [-Wimplicit-function-declaration]
  374 |       entry = getservbyport (htons (scm_to_int (name)), protoname);
      |                              ^~~~~
  make[3]: *** [Makefile:3446: libguile_3.0_la-net_db.lo] Error 1

なぜかというと、よくわからないんだけど guile では、中に標準?ヘッダーファイルを生成してそれを使っているため、 msys2 では netinet/in.h でインクルードされている cygwin/in.h がインクルードされていないという問題が起こる。

なので、 $(top_srcdir)/lib/netinet/in.h に以下のように書いておく必要がある::

#ifdef __CYGWIN__
#include <cygwin/in.h>
#endif

こうすると、すんなりビルドできる。 それで、この $(top_srcdir)/lib/netinet/in.h は、 ./configure を実行すると、元に戻る気がするので注意。

yaourt は衰退しました

yaourt が死んでしまっていた*1ので、trizen をインストールした。

Perl 製であり、pacman と同じ様なコマンドラインオプションを持ってるっぽいのでいんすとーるをキメた。

あと、Antergos が死んでしまった話もする…?

参考

*1:全然 Linux マシンを動かしていないのがバレバレである

空気ねこにもおおよそ分かるにんげんは牛ではないことを RSpec で証明してみた

ネットミームをコードで表現してみるかもしれないシリーズ。

まあ、にんげん(Human)と牛(Cow)の抽象クラス Animal を定義する:

# lib/animal.rb
class Animal
end

中身は何も無いけど、そのうち実装されるっしょ。ヘーキヘーキ。
ここら辺で Animal クラス必要ないなって思ったけど、まあいいか。
ああ、次は牛とにんげんだ…。

# lib/cow.rb
require_relative 'animal'

class Cow < Animal
end

次はにんげん。

# lib/human.rb
require_relative 'animal'

class Human < Animal
end

何も中身ないけど、ヘーキヘーキ。
ということで、スペックファイルを書いてみよう。

describe Human do

  it 'にんげんは牛ではない' do
    # TODO: ここでにんげんは牛ではないことをしょーめーする
  end

end

ここで describe のブロックの中で Humandescribed_class って書けるらしい。
さて、にんげんは牛ではないことを調べるにはどうすればいいだろう?
とぼけるのも疲れてきたので、長年温めてきた常識を働かせてみると、明らかに HumanCow は別のものだ。

つまり:

if Human != Cow then
  puts 'にんげんは牛じゃないよ!'
else
  puts 'ふえぇぇ………、にんげんは牛だったようです………'
end

ってやって、「にんげんは牛じゃないよ!」って表示されればいいわけだ。そうだよね?
こーいうのを RSpec でかっこよく書きたい。 RSpec ではテストする主体?を except() に渡す。それで、 .to ってやって…… 同じかどうか調べるには equal() に調べたい値を渡す。

except( described_class ).to equal( Cow )

いいぞ!
described_class の替わりに Human って書いても良い。

except( Human ).to equal( Cow )

いいね!
でもちょっと待って。
こうすると、HumanCow は同じかどうか調べることになってしまう!
どうしよう?!

.to の替わりに .to_not を使うことで、式の否定版にすることができる。
じゃあ、こんな感じかな?

except( described_class ).to_not equal( Cow )

うまくいった!
it の中に移してみよう:

describe Human do

  it 'にんげんは牛ではない' do
    except( described_class ).to_not equal( Cow )
  end

end

おしまい。

完成したのが こっちにあるので、てきとーに答え合わせしてみてね。