「標準モジュール」とは何ものなのか

「標準モジュール」とは何ものなのか

割と最近まで、「標準モジュール」というのは、単に【コードを書く場所】ぐらいの雑なとらえ方で済ませていた。

しかし、「クラスモジュール」とか、「フォームモジュール」、「シートモジュール」、「ThisWorkbookモジュール」などを使い分けていくうちに、改めて「標準モジュールとは何ものなのか」という疑問が生じたわけである。

標準モジュールはNewできない

たとえば、標準モジュールを挿入し、オブジェクト名を「Foobar」とする。

f:id:akashi_keirin:20180406165212j:plain

で、こいつをNewしようとすると、

f:id:akashi_keirin:20180406165221j:plain

「不正」呼ばわりw

標準モジュールというものは、「オブジェクト」ではあるものの、インスタンス化はできない模様。

ちなみに、FormモジュールはNewできる。

akashi-keirin.hatenablog.com

静的(static)クラスっぽい?

インスタンス化できない、といえば、静的クラスみたいなもんだろうか。

ちょっとメソッドを持たせてみる。

リスト1 標準モジュール「Foobar」
Option Explicit

Public Sub hoge()
  Call makeUserSick("ホゲーーー♪")
End Sub

Private Sub fuga()
  Call makeUserSick("ふがふが")
End Sub

※makeUserSickメソッドのコードはコチラ

PublicメソッドとPrivateメソッドをそれぞれ1つづつ持たせてみた。

Publicメソッドだと、

Foobar.hoge

とモジュール名を書かなくても、

hoge

だけで呼び出せてしまって、イマイチ。

もし、

akashi-keirin.hatenablog.com

このときのように、モジュール名を指定すればPrivateメソッドでも実行できるとなれば便利だと思った。

次のコードで実行してみた。

テストコード 標準モジュール「Module1」
Public Sub testFoobar()
  Call hoge
  Call fuga
End Sub

これは、当然

f:id:akashi_keirin:20180406165231j:plain

エラーになる。当たり前だ。

次は、Privateなfugaメソッドにモジュール名を指定してみる。

テストコード 標準モジュール「Module1」
Public Sub testFoobar()
  Call hoge
  Call Foobar.fuga
End Sub

f:id:akashi_keirin:20180406165241j:plain

コーディング中にintellisenseが働かないのはあのときと同じなので気にしない。

すると、

f:id:akashi_keirin:20180406165249j:plain

アチャー、ダメかw

残念!

モジュール名を指定しないと使えない、とかだったら便利だと思ったんだけどなあ。

ならばクラス(Static)変数はどうか

標準モジュールでもPropertyを持たせることができるので、クラス変数的なものは持たせられるのではないか、と考えた。

リスト1に次のようにコードを追加する。

スト2 標準モジュール「Foobar」
Option Explicit

Private Foo_ As Integer

Public Property Let Foo(ByVal bar As Integer)
  Foo_ = bar
End Property

Public Property Get Foo() As Integer
  If Foo_ = 0 Then Foo_ = 1
  Foo = Foo_
End Property

Public Sub hoge()
  Call makeUserSick("ホゲーーー♪" & " Fooプロパティは「" & Foo & "」やでw")
  Foo_ = Foo_ + 1
End Sub

Public Sub fuga()
  Call makeUserSick("ふがふが" & " Fooプロパティは「" & Foo & "」やでw")
  Foo_ = Foo_ + 1
End Sub

Fooというプロパティを設定し、hoge、fugaメソッドを実行するたびにFooプロパティをインクリメントする。

たったこれだけ。Fooプロパティの値は、hoge、fugaメソッド実行時に表示されるようにしてある。

んで、次のコードを何度か実行してみる。

テストコード 標準モジュール「Module1」
Public Sub testFoobar()
  Call Foobar.hoge
  Call Foobar.fuga
End Sub
実行1回目

f:id:akashi_keirin:20180406165300j:plain

f:id:akashi_keirin:20180406165310j:plain

Fooプロパティは、「2」になっている。

実行2回目

再度実行してみる。

f:id:akashi_keirin:20180406165322j:plain

f:id:akashi_keirin:20180406165331j:plain

FoobarのFooプロパティは、testFoobarプロシージャの実行終了後も値を保持し続けている。

クラス変数っぽいといえばクラス変数っぽいけれど、そもそもインスタンス化できないのだから、何に役立つのか分からないw

ちなみに、オブジェクト名「Room」というクラスモジュールの宣言セクションに「numberOfRooms」というPublic変数を置いて、

Dim r As New Room
Debug.Print Room.numberOfRooms

と書いたとしても、実行すると

f:id:akashi_keirin:20180406165344j:plain

無情にもコンパイル・エラーになる。

まとめ

およそ、次のようなことが分かった。

  • 標準モジュールはNewできない。
  • モジュール名を指定してもPrivateメソッドは別モジュールから呼び出せない。
  • プロパティを持たせることで、クラス(static)変数っぽいことはできる。
  • クラスモジュールではクラス(static)変数を持たせることができない。

おわりに

「標準モジュール」、「クラスモジュール」ともに一長一短があるんだよなあ……。

@akashi_keirin on Twitter