kagamihogeの日記

kagamihogeの日記です。

JEP 326: Raw String Literalsをテキトーに訳した

http://openjdk.java.net/jeps/326

JEP 326: Raw String Literals

Owner    Jim Laskey
Created 2018/01/23 15:40
Updated 2018/04/03 18:29
Type    Feature
Status  Candidate
Component   specification / language
Scope   SE
Discussion  amber dash dev at openjdk dot java dot net
Effort  M
Duration    M
Priority    3
Reviewed by Alex Buckley
Endorsed by Brian Goetz
Release tbd_major
Issue   8196004

Summary

Java言語にraw string literalsを追加します。raw string literalは複数行のソースコードに展開可能で、\nや、\uXXXX形式のユニコードエスケープなど、エスケープシーケンスを解釈しません。

Goals

  • 以下により開発者の効率を高めます。
    • Javaのインジケータを使わない、読みやすい形式の文字列表現
    • supply strings targeted for grammars other than Java
    • 改行用の特別なインジケータを使わずに複数行のソースに展開できる文字列
  • raw string literalsは従来の文字列リテラルと同等な文字列を表現可能、ただしプラットフォーム固有の改行は除く。
  • エスケープの現行のjavac文字列リテラル処理および左マージンのトリムと同様なことをするライブラリ

Non-Goals

  • 新規のString演算子は導入しない。
  • Raw string literalsは文字列補間をすぐにはサポートしません。将来のJEPで導入する可能性はあります。
  • 従来の文字列リテラルには変更はありません。これには以下を含みます。
    • 開始・終了ダブルクオートの繰り返しによるデリミタのカスタマイズ
    • エスケープシーケンスの処理

Motivation

エスケープシーケンスはJavaを含め多くのプログラミング言語で定義されており、直接書くのが難しい文字を表現するのに使います。たとえば、エスケープシーケンス\nはASCIIの改行を意味します。二行で"hello"と"world"を表示するには、文字列"hello\nworld\n"を使います。

System.out.print("hello\nworld\n");

以下のような表示になります。

hello
world

可読性に難点がある他、この例はUNIXベースのシステムをターゲットにしていますが、それ以外のOSでは\r\n(Windows)など異なる改行表現を使用する場合があります。Javaには、printlnなど高レベルのメソッドがあり、これはプラットフォームに適切な改行文字を使用します。

System.out.println("hello");
System.out.println("world");

GUIライブラリで"hello"と"world" を表示する場合、制御文字は意味が無い場合があります。

エスケープシーケンス、バックスラッシュ、はJavaの文字列リテラルでは\\です。二重のバックスラッシュはLeaning Toothpick Syndrome*1を生み出し、過剰なバックスラッシュが文字列の理解を難しくさせます。Javaデベロッパは以下のような例を良く使います。

Path path = Paths.get("C:\\Program Files\\foo");

ダブルクオート文字を使うための\"などのエスケープシーケンスも同様に非Javaプログラマが見る場合に理解を難しくさせます。例えば、ダブルクオートを含む文字列を検索するには以下のようになります。

Pattern pattern = Pattern.compile("\\\"");

実際のところ、エスケープシーケンスは例外的事項でありJavaの日常的な開発に出てくるものではありません。制御文字を使う機会は少なく、エスケープの存在は可読性とメンテナンス性に悪影響を及ぼします。Once we come to this realization, the notion of a non-interpreted string literal becomes a well reasoned result.

現実のJavaコードには、他のプログラム(SQL, JSON, XML, 正規表現など)のコードを埋め込むことがあり、これらは、ユニコードエスケープ・バックスラッシュ・改行を除くと、リテラル文字列そのままでキャプチャされる仕組みを必要とします。

本JEPの提案は、raw string literal、という新しい種類のリテラルを提案します。Javaエスケープと行端仕様とは別途で、多くの状況下で既存の文字列リテラルよりも可読性とメンテナンス性に優れる文字列を提供します。

File Paths Example

Traditional String Literals

Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar");

Raw String Literals

Runtime.getRuntime().exec(`"C:\Program Files\foo" bar`);

Multi-line Example

Traditional String Literals

String html = "<html>\n" +
              "    <body>\n" +
              "          <p>Hello World.</p>\n" +
              "    </body>\n" +
              "</html>\n";

Raw String Literals

String html = `<html>
                   <body>
                       <p>Hello World.</p>
                   </body>
               </html>
              `;

Regular Expression Example

Traditional String Literals

System.out.println("this".matches("\\w\\w\\w\\w"));

Raw String Literals

System.out.println("this".matches(`\w\w\w\w`));

Output:

true

Polyglot Example

Traditional String Literals

String script = "function hello() {\n" +
                "   print(\'\"Hello World\"\');\n" +
                "}\n" +
                "\n" +
                "hello();\n";
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval(script);

Raw String Literals

String script = `function hello() {
                    print('"Hello World"');
                 }
hello();
            `

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval(script);

Output:

"Hello World"

Database Example

Traditional String Literals

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = ‘INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

Raw String Literals

String query = ``
                 SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
                 WHERE `CITY` = ‘INDIANAPOLIS'
                 ORDER BY `EMP_ID`, `LAST_NAME`;
               ``;

Description

raw string literalはリテラルの新しい形式になります。

Literal:
  IntegerLiteral
  FloatingPointLiteral
  BooleanLiteral
  CharacterLiteral
  StringLiteral
  RawStringLiteral
  NullLiteral

RawStringLiteral:
  RawStringDelimiter RawInputCharacter {RawInputCharacter} RawStringDelimiter

RawStringDelimiter:
    ` {`}

raw string literalは1文字以上をバッククオート` (\u0060) (backquote, accent grave)のシーケンスで囲みます。raw string literalは1つ以上のバッククオートで開始し、同数のバッククオートで終了します。異なる個数のバッククオートは文字列の一部として扱います。

raw string literal内へのバッククオートの埋め込みは開始終了のバッククオートの数を増減させることで対応可能です。

raw string literalの文字は、CRとCRLFを除き、解釈を行いません。CR(\u000D)とCRLF(\u000D\u000A)は常にLF(\u000A)に変換されます。この変換はプラットフォーム間の振る舞いの驚きを最小にするためです。

バッククオートの開始があるが対応する終了が無い場合コンパイル時エラーになります。

Java言語仕様では従来の文字列リテラルには二種類のエスケープ、ユニコードエスケープとエスケープシーケンス、を規定しています。Raw string literalsはエスケープを解釈しません。つまり、エスケープ文字列はそのままになります。

\uxxxx形式のユニコードエスケープは、字句解析による解釈前に文字列入力の一部として処理されます。raw string literalの要求をサポートするために、字句解析がバッククオートの開始を見つけたらユニコードエスケープ処理を無効化し、終了したら再度有効化します。一貫性を保つため、ユニコードエスケープ\u0060は、バッククオートの代替としては使いません。

以下はraw string literalsの例です。

`"`                // a string containing " alone
``can`t``          // a string containing 'c', 'a', 'n', '`' and 't'
`This is a string` // a string containing 16 characters
`\n`               // a string containing '\' and 'n'
`\u2022`           // a string containing '\', 'u', '2', '0', '2' and '2'
`This is a
two-line string`   // a single string constant

classファイルでは、ある文字列定数がraw string literalか従来の文字列リテラル由来かどうかは記録しません。

従来の文字列リテラル同様、raw string literalは常にjava.lang.String型です。raw string literals由来の文字列も、従来の文字列リテラル由来の文字列と同様の扱いです。

Escapes

エスケープシーケンスを解釈しない複数行文字列を開発者が望む可能性は高いです。この要求に応えるため、Stringクラスにエスケープシーケンスを実行時に解釈するインスタンスメソッドを追加します。

public String unescape()

このメソッドは、JLSが定義しているエスケープシーケンス(3.3 Unicode Escapes, 3.10.6. Escape Sequences for Character and String Literals)と同一スペルの\を頭につけた文字を、そのエスケープシーケンスが表現する文字に変換します。

例(b0からb3はtrueになる)

boolean b0 = `\n`.equals("\\n");
boolean b1 = `\n`.unescape().equals("\n");
boolean b2 = `\n`.length == 2;
boolean b3 = `\n`.unescape().length == 1;

エスケープ変換を細かく制御できるメソッドを提供します。

また、エスケープ反転ツール用のメソッドもあります。以下のメソッドもStringに追加します。

public String escape()

このメソッドは、' 'より小さいすべての文字をUnicodeかcharacter escape sequencesに変換し、'~'より上の文字はUnicode escape sequencesに変換、", ', \エスケープシーケンスに変換します。

例(b0からb3はtrueになる)

boolean b0 = "\n".escape().equals(`\n`);
boolean b1 = ``.escape().equals(`\u2022`);
boolean b2 = "•".escape().equals(`\u2022`);
boolean b3 = !"•".escape().equals("\u2022");

Source Encoding

ソースファイルに非ASCII文字がある場合、javacコマンド(javac -encoding)で正しいエンコーディングを使う必要があります。もしくは、raw stringに適切なUnicodeエスケープをし、Unicodeエスケープを適切な非ASCIIに変換するライブラリを使用します。

Margin Management

複数行文字列の課題の一つに、左マージン(いわゆるヒアドキュメント)か、周囲のコードのインデントで文字列をフォーマットするか、があります。理想的には、文字列は周囲のコードとブレンドさせたいです。よって問題は、余分な左スペースの扱い方をどうするか、になります。

柔軟に対処出来るようにするため、raw string literalsのマージンはスキャンされます。余分な左スペースをトリムするメソッドをStringに追加する予定です。

Alternatives

Choice of Delimiters

従来の文字列リテラルとraw string literalは両方ともデリミタで文字シーケンスを囲みます。従来の文字列リテラルは開始・終了のデリミタにダブルクオート文字を使います。この対称性によりリテラルの読み込みとパースは簡単です。raw string literalも対称性のあるデリミタを用いますが、別の異なるデリミタを使う必要があり、これは文字シーケンス内にエスケープを付与しないダブルクオートを使う可能性があるためです。raw string literalのデリミタの選択には以下の考慮事項があります。

  • デリミタは短い文字列・マージン管理・一般的な可読性で効果的であるように大仰なものにならないこと。
  • 開始デリミタはその後にraw string literalのボディが続くことを明確に示すこと。
  • 終了デリミタは文字列にあまり出てこないものなこと。終了デリミタが文字列内に出現する場合、終了デリミタの埋め込みルールは明確かつシンプルなこと。埋め込みはエスケープ無しの実現が必須です。

デリミタには今のところ3つのLatin1文字、single-quote, double-quote, and backtick、としています。それ以外は明快さに影響を及ぼし、従来の文字列リテラルとの間に一貫性を欠くと考えています。

従来の文字列リテラルとraw string literalとに違いを出す必要があります。ダブルクオート以外の文字かカスタムフレーズである種の複合デリミタを作ることにより、raw string literalsでダブルクオートを使うことは出来ます。たとえば$"xyz"$abcd"xyz"abcdなどです。これら複合デリミタは基本的な要件は満たしますが、明快さに欠け、終了デリミタの埋め込みはシンプルではありません。Also, there is a temptation in the custom phrases case to assign semantic meaning to the phrase, heralding another industry similar to Java annotations.

連続クォート、"""xyz"""、について。これについては曖昧さを回避するのが面倒です。たとえば"" + x + ""は、従来文字列リテラル+変数+従来文字列リテラルの結合としても、" + x + "という7文字の raw string literalとしてでもパースが可能です。

バッククオートの利点は別の目的で使われない点です。連続クオートと空文字で発生する曖昧さを回避できます。Java言語仕様の用語における新しいデリミタになります。バッククオートは、シンプルな埋め込みルールを含め、デリミタの要求をすべて満たします。

デリミタの選択における別の考慮事項は将来の技術発展の可能性です。rawおよび従来の文字列リテラルの両方でシンプルなデリミタを使用するようなことが、将来の技術では出来るかもしれません。

このJEPではバッククオートを提案します。言語の現在のクオートとは異なりますが、同様の目的を果たします。

Multi-line Traditional String Literals

このオプションはraw string literalとは別モノですが、raw string literalsに加えて従来の文字列リテラルに複数行機能を持たせることも合理的かもしれません。この機能を有効化すると従来の文字列リテラルの複数行をエラーにするツールとテストに影響が出る可能性があります。

Other Languages

Javaは、raw stringsを言語レベルでサポートしない、数少ない現代的なプログラミング言語グループの1つに取り残されています。

以下の言語、C, C++, C#, Dart, Go, Groovy, Haskell, Java, JavaScript, Kotlin, Perl, PHP, Python, R, Ruby, Scala, Swift、はraw string literalsをサポートしており、デリミタとrawおよび複数行文字列の使用方法について調査しました。Unixツールのbash, grep, sedの文字列表現も調査しました。

複数行リテラル問題の解消には、従来の文字列リテラルのダブルクオートのボディでCRとLFを使えるようにJava仕様を変更する、という手法もあります。ただし、そういうダブルクオートの使い方ではエスケープの解釈が必要です。

異なる解釈の振る舞いを明示するには、異なるデリミタが必要です。Java以外の言語では様々なデリミタを採用しています。

Delimiters Language/Tool
"""...""" Groovy, Kotlin, Python, Scala, Swift
`...` Go, JavaScript
@"..." C#
R"..." Groovy (old style)
R"xxx(...)xxx" C/C++
%(...) Ruby
qq{...} Perl

Python, Kotlin, Groovy and Swiftはraw stringsにはダブルクオート3つを使います。これは既存の文字列リテラルとの連続性を反映したものです。

Go and JavaScriptはバッククオートです。文字列であまり使われない文字を選択しています。Markdownとの相性は良くないですが、大半の場合では問題ありません。

異色どころでは、C#@"..."などのメタタグは本JEPで提案するバッククオートと機能的に似ています。しかし、@Javaではアノテーションを示唆します。そうしたメタタグの使用法を持ち込むことは、将来的にそのメタタグの使用を制限します。

Heredoc

raw stringsのクオートの別案にヒアドキュメント*2があります。ヒアドキュメントはUnixシェルで最初に使われ始め、Perlなどに導入されました。ヒアドキュメントにはプレースホルダとエンドマーカがあります。プレールホルダは文字列をコード内に挿入する場所とエンドマーカを指定します。エンドマーカ―は文字列の最後につけます。

System.out.println(<<HTML);
<html>
    <body>
        <p>Hello World.</p>
    </body>
</html>
HTML

ヒアドキュメントはraw stringsの一つの案ではありますが、アナクロに思われます。さらにマージン管理の問題がやはり発生して複雑化します。

Testing

従来の文字列リテラルをraw stringリテラルで置き換えたテストのコピーを作成し、Stringのテストスイートを拡張します。

行端およびコンパイル単位の終了時におけるコーナーケースのテストをネガティブテストに追加します。

エスケープとマージン管理のメソッドのテストを追加します。

Risks and Assumptions

本JEPの仮定として、Markdown, Go, JavaScriptを含むraw string literalsにはバッククオートがあまり出現せず、そのため、バッククオートを繰り返すデリミタなら他よりも煩わしくない、としています。

*1:Leaning Toothpick、つまり斜めに傾けたつまようじが大量に並んでる様を揶揄する言葉

*2:"here" documents or heredocsが原文なんだけど「ヒアドキュメント」一つにまとまてしまった

Spring BootでRabbitMQの送受信

Spring BootとSpring AMQPを使用してRabbitMQの送受信を行う。hello worldレベルのことをやる。ドキュメント的には https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#boot-features-amqp のあたり。

準備

RabbitMQのインストールとGUIの管理画面を使えるようにしておく。

依存性の追加

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
    </dependencies>

設定

ローカルにRabbitMQをインストールしてデフォルト設定の場合、特に何も設定しなくても良い。別マシンに接続するとか、ID・パスワードを入れるとかの場合、externalized configurationで設定する。以下はapplication.yamlでの設定例。

spring:
  rabbitmq:
    host: 192.168.10.23
    port: 5672
    username: kagamihoge
    password: xxxxxx
  main:
    web-environment: false

RabbitMQと直接の関係は無いが、web関連は不要なんでspring.main.web-environment=falseで抑制しておく。

指定可能な値の一覧 -> https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#common-application-properties

受信

package kagamihoge.receive;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ReceiverApplication {
    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(ReceiverApplication.class, args);
    }

    @RabbitListener(queues = "sample-queue")
    public void receive(String msg) {
        System.out.println(msg);
    }
}

動かす前に http://localhost:15672 の管理コンソールからキューを、sample-queueという名前で、新規作成しておく。

動作確認は管理コンソールからメッセージ送信する。sample-queueを選んでPublish messageする。Propertiesにcontent_type=text/plainと入れればbyte[]じゃなくて文字列を送信できる。

送信

package kagamihoge.send;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SenderApplication implements CommandLineRunner {
    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(SenderApplication.class, args).close();;
    }

    @Autowired
    AmqpTemplate amqpTemplate;

    @Override
    public void run(String... args) throws Exception {
        Message message = new Message("msg".getBytes(), new MessageProperties());
        amqpTemplate.send("sample-exchange", null, message);
    }
}

動かす前に管理コンソールでexchangeをsample-exchangeという名前で作り、sample-queueにバインドさせておく。

受信側を起動させておいて、上の送信のコードを動かす。sample-exchangeに送信したメッセージがsample-queueに入って、それを受信、という流れが確認できる。

アトラス作品ファンのオフ会 真・眼鏡祭Ⅳ(2018/04/07)に行ってきた

4/7 真・眼鏡祭Ⅳ - Twiplaに行ってきました。

f:id:kagamihoge:20180407142821j:plain

眼鏡祭はペルソナを初めとするアトラス作品ファンコミュニティの大規模オフ会です。参加者数は200人強と、当日がPERSONA5 the Animationの第一話放映日、P3D - ペルソナ3 ダンシング・ムーンナイトおよびP5D - ペルソナ5 ダンシング・スターナイトの発売を控えてか、今回も大変な盛況ぶりでした。天気予報では雨が危ぶまれましたが、天候は晴れ。場所はキリストンカフェ東京を貸し切っての開催です。

当日の様子はTwitterハッシュタグ#眼鏡祭0407から追えます。

アトラス作品のコスプレがたくさんいるオフ会

眼鏡祭の特徴は、色々ありますが、なんといっても目を引くのはコスプレOKな点です。

こちらの全体写真はコスプレ参加者ほぼ全員の集合写真です。キャラクターの分布としては、今回はやはりP5が一大勢力でした。怪盗団やサブキャラクター、早くもP5D衣装の方もいました。ジョーカーは当然のように大人気です。参加者総数のうち7~8割は何らかのコスプレをしているため、集合写真のインパクトはかなりのインパクトがあります。

P5の勢いがあるため他作品は相対的に少ない傾向にありました。しかし、P3やP4のダンス衣装、D×2 真・女神転生 リベレーション魔神転生、女神異聞録、ペルソナ2、など、今となっては懐かしい作品をこよなく愛するコスプレの方、異形の悪魔コスなど、P5と比べれば少数派であっても、相変わらず存在感がありました。

主催曰く「コンテンツは参加者自身」

眼鏡祭はいわゆるオフ会で、その目的は参加者同士のリアルなコミュニケーションです。お酒を飲み、コスプレ肴に、ゲーム・アニメ・マンガなどオタクの話題で気兼ねなく一日中盛り上がる。基本的にはそれだけです。しかし、コスプレを良くするレイヤーさんに聞いてみても、コスプレOKで交流がメイン、しかもアトラス作品に絞った会でここまで大規模なものは他に無いようです。このシンプルだが強力なコンセプトに様々な人が魅力を感じ、集まって来ています。

参加者の年代は、10年近く続いている会ゆえに、30代以上が多数です。ただし、アトラス作品はP5が初めてで眼鏡祭に来た、という20代もかなり居ます。おおむね1~2割は初参加で、初めて来たのが自分だけ、という事にはなりません。新しい方がどんどん来るので、する事は毎回同じでも、いつも新鮮な驚きがあるのが眼鏡祭のすごいところです。

コスプレは最高の会話のきっかけ

眼鏡祭ではコスプレを仮装と呼びます*1。200人超のイベントで何らかの会話のとっかかりを作るのは、普通に考えれば相当な困難です。そこでコスプレの出番ですが、コスプレと呼べるほど凝ったもので無くてもいい、という意味を込めて「仮装」と呼ばれています。

あるキャラのコスプレをしてるということは、そのキャラや作品に何らかの思い入れがある、その意思表示です。コスプレをとっかかりにして会話が広がっていくのは眼鏡祭ではありふれた光景です。そのためにコスプレを眼鏡祭でだけはする、という人も一定数存在します。

もちろんコスプレはそれなりの敷居があります。凝ろうとすれば果てが無いですが、簡単なもので眼鏡祭は十分。コスプレに抵抗があるなら、普段使いの難しい各種のグッズを身に付けたり、モルガナのぬいぐるみを持ってきたり、千枝ちゃんのジャージ羽織るだけでも違います。

眼鏡祭ではコスプレの撮影がメインではなく、コミュニケーションの切欠にするのがメインの目的です。テーマパークでテンションを高めるためにグッズや簡単なフェイスペイントなどをしますが、大半の参加者がコスプレをする眼鏡祭はある意味アトラクションのため、自らのテンションを高めないと会場の熱気に押し負けます。そのため、何らかの手段で己のゲージを高めて、色々な人と交流しやすくすることが推奨されています。

初参加しやすくする仕掛け

眼鏡祭には様々な初参加者向けの仕組みがあります。200人のイベントにいきなり放り込まれても困りものなため、まず来場すると7~8人に分けられたテーブルにつきます。この少人数グループで自己紹介(=好きな作品や推しキャラを語ること)をし、乾杯後は自由時間となります。

なお、不安なので知り合い同士で同じテーブルに座りたい、など初参加者向けの配慮は出来る限り応じてくれるため、申込フォームや主催のツイッターなどにあらかじめ書くと良いです。

それで実際のところ初参加で楽しめるのか? については、ステマっぽいですが、実際に初参加の方のツイートを見ると雰囲気が伝わってきます。

コスイベとは違う点がいくつか

一つ注意点があるとすれば、いわゆるコスプレイベントとは性質がかなり違います。例えば、会場はカフェ・レストランなので、撮影スタジオに比べると設備的にはどうしても劣ります。照明は控え目ですし、更衣室はフロアを区切っただけなので暗めな上にさほど広くはないです。特に女子更衣室は年々コスプレ参加者の増加に伴い中々難しい状況にあるようです。

みんなで作る眼鏡祭

眼鏡祭の運営は有志スタッフが行っています。会場や飲食は別にすると、その他すべては有志に頼っているため、眼鏡祭では運営スタッフを募集しています。

眼鏡祭の運営は多岐に渡ります。当日目に見える仕事だけでも、会場設営・受付・更衣室管理・全体進行係に各テーブル進行係があり、ノベルティのイラストや、名札や進行表印刷など各種物品の準備など。金銭管理や会場予約など事務作業もあります。200人を一日中動かす企画・運営なので、世の中に存在するスキルのほとんどはどこかしらで出番があります。

眼鏡祭は本当にすごいイベントで、これに感謝を示す方法は色々ですが、運営スタッフに参加してみるのも一つの手と言えるでしょう。

眼鏡祭から次につなげる

実を言うと、眼鏡祭の当日だけで知り合いを増やすのは至難の業です。200人も居るので覚えるのも覚えられるのも大変な苦労を伴うためです。そのため、もうちょっと人数の少ない眼鏡祭関連のイベントに顔を出してみるのをオススメします。

まずは眼鏡祭おつかれ的なおかわり会。こちらは単なる飲み会です。

ガンプラをわいわい言いながら作る会。

以下は眼鏡祭関連のイベントではないですが、眼鏡勢で行く人はかなり居ると予想されます。

次回の眼鏡祭は7/28に決定したようです。

他にも、眼鏡祭界隈にはお祭り好きがたくさんいるので、食べ歩きやら聖地巡礼やらP3D・P5Dに向けたダンス練習会やら、多種多様なことをやっている人がいます。お誘いがあれば気軽に足を運んでみてはいかがでしょうか。

さいごに

主催のマソーさんはじめ運営スタッフの皆さん、当日俺の話し相手になって頂いた方、常連顔なじみの皆さんなど、今回も非常にたのしい一日を過ごすことが出来ました。また、この日記を書くにあたり、眼鏡祭の雰囲気を伝えるには極めて効果的なため、沢山のツイートを引用させて頂いた方*2にも感謝致します。

それでは次回もよろしくお願い致します。

URL一覧

*1:この日記では一般的な分かりやすさ優先で「コスプレ」を使います

*2:問題があれば面倒ですが https://twitter.com/kagamihoge にお願いします。