へっぽこ社会人4年生がプログラミングを頑張る

へっぽこ社会人4年目がプログラミング系統を中心に書きたいことをつらつらと書きます

DojoCon Japan 2022 参加レポート Part 1

2022/11/28 に富山商工会議所で開催された DojoCon Japan 2022 に参加してきました。 3 年ぶりの現地開催ということで、全国各地の Dojo のチャンピオンやメンターがたくさん来場していました。

2019 年の参加レポート記事 同様に、今回の参加レポートも複数記事に分けて執筆します。 2019 年の参加レポートは、全部リリースするまでに約半年もかかってしまいましたが、今回は記憶が新しいうちに、参加レポートを書き切りたいと思います (笑) (あくまでベストエフォートですw)

Keynote

Keynote では CoderDojo 瑞穂 のニンジャとして活動している、前田優花さん、川口明莉さん、馬場音和さん、宇枝梨良さんによる、「みてきいて!世界を目指した私たちの 5ヶ月! 〜Technovation Girls Regional Winner Asia 〜」という題目の発表でした。

4 人のニンジャがチームで Technovation Girls という国際的なプロジェクトに挑んだ際の活動について発表されていました。 スマホ用の節水アプリを開発し、コンテストに応募したとのことです。

世界への挑戦の第一歩

Technovation Girls への挑戦のきっかけは、 Dojo のチャンピオンから、コンテストに参加してみないかと誘われたこと だったそうです。 4 人で協力してチャレンジすることが面白そうと思ったこと も挑戦の動機となったそうです。 もし 1 人だけでの挑戦だったら、不安で参加しなかったかもしれないとのことでした。

4 人はプロジェクトに挑戦する前から交流があったわけではなかったそうです。 最初は面識がなかったけれど、交流を深めることで仲良くなっていきました。

コンテスト終了までの間、毎週 Zoom で定例ミーティング をし、 議事録を作って Scrapbox に保存して共有 していたそうです。 定例以外でも、細かな連絡は Discord を使ってやり取りをしていたそうです。

様々な課題を乗り越えて

作品を作るまでには、様々な課題を乗り越える必要がありました。

  • テーマについての理解
  • 開発に関する課題
  • 発表に関する課題

テーマについての理解

コンテストのテーマは SDGs についてでした。 しかし、そもそも SDGs とは何かを知らない状態からのスタートだったので、まずは SDGs についての勉強をしたそうです。

SDGs のテーマに沿って、何を作るかのアイデアを 4 人で出し合い、たくさん出たアイデアの中から、まずは 5 つに候補を絞り込んだそうです。 さらにその中から、基準を決めて採点して、節水アプリの開発に決まったそうです。

開発に関する課題

開発に関しては、様々な課題に取り組む必要がありました。

スマホアプリとして開発するために、 AppInventor を利用することにしたのですが、 日本語の情報が少なく、勉強するのに苦戦した そうです。 日本語の情報がないので、外国語で解説されている YouTube の動画を見ながら勉強したとのことでした。

節水アプリを作る上で、 AppInventor の AI の機能を用いて、シャワーの音からどの程度シャワーの水が使われているかを測定する機能を実現したそうです。 しかし、より精度を上げるために、流水計も試してみることにしたそうです。

Micro:bit で電子工作をすれば実現できそうということで、 Amazon で流水計を購入したそうです。 しかし、説明書がなく、流水計が感知した水量の値を取得する方法を見つけるのに苦戦したようです。

水が流れると、流水計がパルス信号を送信して、水量が計測できるようにできたそうです。

発表に関する課題

アプリが完成しても、課題はまだありました。

コンテストの作品を発表するためには、動画を作成する必要がありました。 また、国際的なプロジェクトということもあり、 英語で発表 する必要がありました。

動画の作り方やスピーチなど、 Dojo のメンターやチャンピオンに相談をして進めたそうです。

プロジェクトを通じて得たもの

コンテストに応募し、 Regional Winner になったそうです。 日本はアジアに所属するので、 アジアでの優勝 にあたるとのことです。 また、別の国内のコンテストにも応募して、賞を取ったとのことです。

今回のコンテストを通じて、大きく 3 つのものを得られたそうです。

  • 友達
  • 技術
  • 経験

プロジェクトを始める前は、 4 人はお互いに面識がありませんでした。 しかし、プロジェクトをきっかけに仲良くなり、新たな友人となりました。

技術の面についても、アプリ開発や電子工作についてたくさんの学びがありました。 また、動画編集や発表などの技術面についても学べる機会となったそうです。

国際的なコンテストに作品を出して発表するという機会は 4 人にとって良い機会となったそうです。 それ以外にも、プロジェクト全体を通して、企画から作品制作、発表までの全体を通して、様々な経験を得られたようです。

質疑応答

質疑応答では、以下のような質問と回答がありました。

  • プロジェクトを進める過程でグループ内で揉めることはあったか? あればどう解決したか?
    • イデアを 1 つに絞る際に言い合いっぽいことはあった
    • 採点方式をとることで決めることができた
  • 普段学校ではどのような学びをしているか?
    • みんなと授業を同じように受けていて、特別なことをしているわけではない
    • SDGs については少し学校で学ぶ機会はあったが、プログラミングは扱わなかった
  • 次チャレンジする人に注意点を伝えるとしたら何があるか?
    • 早めに行動することが重要
      • 特にアイデア出しに時間がかかる
    • 得意分野で分担を決めると良いかもしれない

所感

国際的なプロジェクトに参加してみよう、というチャレンジ精神がとても良いなと感じました。 特に、コンテストに出す作品について、英語でプレゼンテーションしなければいけないので、心理的なハードルも高いはずです。 それでも、 みんなで協力してチャレンジするのであれば面白そう という好奇心旺盛さが、ニンジャならではだと感じました。

4 人でプロジェクトのアイデア出しから開発、発表もし、コンテストで Regional Winner という成果を挙げられたことも凄いと感じました。 定例会議をして、さらに議事録を作って共有もし、 大人顔負けのプロジェクト管理をしていた のも感心しました。

コンテストに作品を出すまでに、 4 人の努力も大きかったと思いますが、 回りのメンター達の助け があったことも、プロジェクトの成功に必要不可欠だったと思います。 コンテストについて、チャンピオンが誘わなければ、そもそも 4 人で挑戦することはなかったかもしれません。 また、 4 人だけでは解決方法が見つからない課題について、メンターという 助け舟を出せる存在がいた ことも、心理的な安心に繋がったのではないかと思います。

CoderDojo は 子供たちが自由にプログラミングを学んだり、何かを作ることができる場 を提供しています。 ただ学んだりモノを作るだけでなく、 Dojo にいるニンジャと交流を深めたり、わからないことを気軽にメンターに聞ける場 でもあると思います。

CoderDojo はプログラミングを学ぶことができる場所という認識をされることが多いと思います。 もちろん、子供たちが自発的にプログラミングを学ぶ場を提供する役割を担っていますが、その場を通じて ニンジャやメンターとのネットワークを作る コミュニティとしての側面もあると考えます。 単にプログラミングを学ぶ場というだけでなく、 プログラミングを通じたコミュニティ であることが CoderDojo の良さだと思います。


プログラミングコンテスト プレゼンテーション

プログラミングコンテストでは、全国のニンジャが応募した作品から、審査を通過した作品の最終審査が行われました。 最終審査では、製作者であるニンジャが 5 分の持ち時間で作品をプレゼンテーションします。

コンテストの審査結果は、来場者の投票によって決まります。 最も良いと思う作品に 1 票投票できます。

作品概要

以下の 5 作品が最終審査の対象でした。

  1. 大切なふるさとの四季

    ランプで住んでいる町の四季を表現した作品です。 プログラミング、工作、切り絵という、作者の好きな要素を詰め込んだそうです。

    最初は Micro:bit 1 つだけで作成しようとしたそうですが、サーボモーターでランプを回転させるときに、配線が絡まって回らなくなったり、電力不足などの課題があったとのことです。 この問題を解決するために、使用する Micro:bit を 2つに増やし、それぞれを通信させることで、ランプの光とモーターの制御を分けたそうです。 Micro:bit で制御する対象を分けたことで、配線と電力不足の課題が解決できたそうです。

  2. ちょいチャレ!

    小さな挑戦を習慣化するための、ちょっとしたチャレンジをランダムに出すアプリ作品です。 新たな挑戦を諦めてしまい、後々後悔することが何度かあったそうです。 小さな挑戦を習慣化すれば大きな挑戦にも躊躇しなくなるのではないかという発想から、この作品を作るに至ったようです。

    様々な挑戦に取り組めるように、70 個もの挑戦を用意したそうです。 また、モチベーション維持のために、達成度に応じてアプリ内の犬が成長するというゲーム性も持ち合わせています。

  3. 欠席君

    ハイブリッド型オンライン授業で、オンライン参加する学生のアクションを教員に伝えるためのロボット型の作品です。 対面とオンラインのハイブリッド型の授業では、オンライン参加でいくつかの課題があり、両立が難しいことが挙げられました。 オンライン参加の学生からは黒板が見えづらかったり、挙手しても教員に気づかれづらいという課題を解決するために、この作品を作ったそうです。

    オンラインシステムそのものを新たに作るのは難しいので、既存のオンラインシステムをサポートする方針で進めることにしたそうです。 カメラ、アーム、 LED を組み込んだロボットを作成し、オンライン参加の学生がロボットに対して操作をすることで、オンライン参加でも教員にアクションを伝えられるようにしていました。 例えば、アームを挙げることで挙手したり、何かしらのトラブルがある場合に LED を点滅させることで、教員にアピールできます。

  4. TeachableMachine – Scraper

    TeachableMachine 1 に学習させる画像を自動的に収集する作品です。 TeachableMachine では、カメラで撮った画像を学習させられて、手軽に学習させることができますが、カメラで撮れないものについては、画像を読み込んで学習させる必要があります。

    学習用の画像を自分で用意するかわりに、 Google 画像検索の結果をスクレイピングして収集し、 TeachableMachine に学習できるようにしたとのことです。 また、学習用の TM ファイルはリバースエンジニアリングをしたとのことでした。

  5. ブロックお絵かき

    模様の入ったブロック単位で絵がかける Scratch プログラムの作品です。 PC では、絵の細かい部分をマウスで描くのが難しいので、模様入りのブロックを用意することで、 PC でも簡単に絵が描けるようにしたそうです。 様々な模様のブロックに加えて、色の調整ができるカラーブロックもあるそうです。

    カラーブロックの実装が苦労した点で、複数の色を 1 つのカラーブロックで分けるのが難しかったそうです。 また、工夫した点として、処理の高速化が挙げられていました。

所感

どの作品も、作成過程での課題や困難があり、それを解決する方法を考えて実現できていることが凄いと感じました。 また、題材も 自分たちの身近な課題 を見つけ、 ソリューションを実現 している作品が多いところも面白いと思いました。 (3 年前も同じようなこと書いた気がする...)

今回のコンテストには、 DojoCon Japan 2019 でもプレゼンテーションをしていたニンジャが発表していて驚きました。 3 年前も面白い作品を作っていて、強く印象に残っていました。 そして、 子供って 3 年でかなり成長する ことを実感しました。

作品で使われている技術についても、発表で初めて聞いたものがいくつかあり、自分にとっても勉強になりました。 TeachableMachine や AppInventor は、発表を聞いて初めて知ったので、自分の知らない技術を知る良い機会となりました。

DojoCon でのプログラミングコンテストは、各地でそれぞれ活動しているニンジャが、どのような作品を作っているかを知ることができる良い機会だと思います。 また、他の Dojo のニンジャがどのような技術を使ってものを作っているかを知ることもできるので、メンターやチャンピオンにとっても、良い機会になるのではないかなと思います。


まとめ・考察

DojoCon Japan の Keynote をニンジャが務めるというのは、面白い試みだと思いました。 国際的なプロジェクトに挑戦した体験談を、ニンジャの目線から聞くことができ、自分にとって良い機会になりました。 Regional Winner という成果が得られたのも、 4 人の積極性 があり、さらに まわりにサポートできる人たちの存在 があったことが大きかったのだろうと思います。

プログラミング・コンテストでは、 3 年前と同様に、ニンジャたちの着眼点に驚かされるばかりでした。 ニンジャが 自身の身の回りで感じる課題 を見つけ、それに対して 解決のアプローチ を考えて実現するという、 大人でもなかなか難しいことを実行できている ことが凄いと感心していました。

今回のニンジャたちの発表を聞いて、積極的に活動してコンテストなどで成果を挙げていることが本当に凄いと感じました。 その一方で、保護者や先生など、まわりの大人たちの比較対象になってしまわないかなとも思いました。 杞憂かもしれませんが、 DojoCon で発表していた子たちは、こんな成果まで挙げれるのに、というような比較対象になってしまわないだろうかという心配も少なからず感じました。

コンテストの審査通過や賞を取ることは、ニンジャたちが積極的に活動した延長線上にあるもので、その過程も重要だと考えます。 偏見かもしれませんが、他の子供の成果と比較してしまう大人 (特に保護者) は決して少なくないのではないかと思っています。 特に、学校の成績などは顕著にこのような面が出ると思います。

子供にプログラミングなど、学校の勉強に置いていかれないように何かさせたいと思う保護者は多いと思います。 しかし、個人的には「させる」ではなく、興味が湧く方法を「一緒に見つける」ことが重要ではないかと考えます。

自分の関心が薄いことに取り組むのは、大人であったとしても決して負担は少なくないはずです。 しかし、「面白い」「楽しい」と感じられることであれば、継続して取り組むことも、そこまで苦ではないのではないでしょうか? 成績などの結果に目が行きがちですが、やはり何かをやり遂げるには、 自発的に継続できること が重要だと思います。 そして、そのきっかけを作るのは、大人も参加できる取り組みではないかと考えます。

もちろん、コンテストで賞を取るなどの成果が挙げられれば、素直に喜ぶべきだと思います。 もしコンテストなどで賞を取れなかったとしても、相手の良かった部分をリスペクトしつつ、自分たちの良かった部分は褒めて、子供たちが自信を持てれば良いのではないかなと思います。

何よりも大事なことは、子供たちが 自発的に取り組みたいと思える何かを持つこと ではないかと考えます。 そして、 CoderDojo は、子供たちにプログラミングに触れる機会を提供し、 自発的にプログラミングを楽しく取り組める場 となっていれば良いなと思います。


Part 2 へ続きます。 次回は聴講したセッションについて執筆する予定です。

[2023/10/29 追記]

執筆から期間が空いてしまったため、打ち切りにします。 すみません...


  1. Google が提供する AI モデルを学習できる Web サービス

C の構造体へのポインタのキャストをちょっと理解する話

前回の記事 C のポインタへのキャストをちょっと理解する話 を書き終えた後、構造体へのポインタのキャストも同じように考えられるのではと思いました。 自分の理解が合っていることを確認するために、実際に簡易的なコードを書いて動かしてみました。 備忘録も兼ねて、構造体へのポインタのキャストについて理解した内容をまとめておこうと思います。

この記事は Cの構造体へのポインタのキャストを考える で解決できなかった疑問に対する自身の回答の記事です。

実行環境と型のサイズ

以下の実行環境で動作確認用のプログラムを実行しました。

また、型のサイズはそれぞれ以下を想定しています。

  • char: 1 byte
  • int: 4 bytes
  • double: 8 bytes

なお、 型のサイズなどは実行環境に依存する ので、 この記事で示すプログラムの実行例と合致しない場合があります。

構造体へのポインタのキャストの動作

構造体へのポインタのキャストの動作を確認するために、 型が異なるメンバ変数で構成された構造体 をそれぞれ定義して、動作の違いを比較してみます。 例として、整数型の座標を表す構造体と実数型の座標を表す構造体をそれぞれ定義し、簡易的な動作確認プログラムを実装します。

図1 のように、メンバ変数の型が int 型で構成される構造体 struct intCoord と、 double 型で構成される構造体 struct doubleCoord を定義します。 struct intCoord のメンバ変数はそれぞれ int 型で定義されているので、メンバ変数のサイズはそれぞれ 4 bytes です。 一方、 struct doubleCoord のメンバ変数はそれぞれ double 型で定義されているので、メンバ変数のサイズはそれぞれ 8 bytes です。

図1. 型が異なるメンバ変数のサイズの比較

この 2 つの構造体について、以下の動作を比較します。

  1. struct intCoord* 型として扱った場合のメンバ変数のアドレスと値を確認
  2. struct doubleCoord* 型として扱った場合のメンバ変数のアドレスと値を確認

サンプルプログラムの実装

それぞれの構造体の定義と手続きの定義の実装例を以下に示します。

#include <stdio.h>

// 整数型の座標を表す構造体
struct intCoord {
  int x;
  int y;
};

// 実数型の座標を表す構造体
struct doubleCoord {
  double x;
  double y;
};

// struct intCoord へのポインタ型の変数やそのメンバ変数のアドレスや値を表示
void printIntCoordAddrAndValue(struct intCoord *arg)
{
  printf("address of arg: %p\n", arg);

  printf("address of arg->x: %p\n", &(arg->x));
  printf("address of arg->x: %d\n", arg->x);

  printf("address of arg->y: %p\n", &(arg->y));
  printf("address of arg->y: %d\n", arg->y);
}

// struct doubleCoord へのポインタ型の変数やそのメンバ変数のアドレスや値を表示
void printDoubleCoordAddrAndValue(struct doubleCoord *arg)
{
  printf("address of arg: %p\n", arg);

  printf("address of arg->x: %p\n", &(arg->x));
  printf("address of arg->x: %lf\n", arg->x);

  printf("address of arg->y: %p\n", &(arg->y));
  printf("address of arg->y: %lf\n", arg->y);
}

int main(int argc, char **argv)
{
  struct intCoord coord1 = {2, 3};
  struct doubleCoord coord2 = {2.71828, 3.14159};

  // 変数 coord1 のアドレスを printIntCoordAddrAndValue() に渡す
  // メンバ変数の値 x, y がそれぞれ正しく表示される
  printf("printIntCoordAddrAndValue(&coord1)\n");
  printIntCoordAddrAndValue(&coord1);
  printf("\n");

  // 変数 coord2 を struct intCoord* にキャストして printIntCoordAddrAndValue() に渡す
  // メンバ変数の値 x, y は 2, 3 とはならない
  printf("printIntCoordAddrAndValue((struct intCoord*)&coord2)\n");
  printIntCoordAddrAndValue((struct intCoord*)&coord2);
  printf("\n");

  // 変数 coord2 のアドレスを printDoubleCoordAddrAndValue() に渡す
  // メンバ変数の値 x, y がそれぞれ正しく表示される
  printf("printDoubleCoordAddrAndValue(&coord2)\n");
  printDoubleCoordAddrAndValue(&coord2);
  printf("\n");

  // 変数 coord1 を struct doubleCoord* にキャストして printDoubleCoordAddrAndValue() に渡す
  // メンバ変数の値 x, y は 2.0, 3.0 とはならない
  printf("printDoubleCoordAddrAndValue((struct doubleCoord*)&coord1)\n");
  printDoubleCoordAddrAndValue((struct doubleCoord*)&coord1);
  printf("\n");

  return 0;
}

1 の処理は printIntCoordAddrAndValue() として、 2 の処理は printDoubleCoordAddrAndValue() として実装しました。 どちらの処理も引数 arg で受け取った引数のアドレスと、それぞれのメンバ変数のアドレスおよび値を表示します。

異なる構造体に直接キャストすることはできない ので、構造体へのポインタにキャスト することで、構造体のデータが格納されているアドレスを基準にそれぞれのメンバ変数が格納されるアドレスにアクセスします。

実行結果

実行結果は以下の通りでした。

printIntCoordAddrAndValue(&coord1)
address of arg: 0x7ff7b10183c8
address of arg->x: 0x7ff7b10183c8
address of arg->x: 2
address of arg->y: 0x7ff7b10183cc
address of arg->y: 3

printIntCoordAddrAndValue((struct intCoord*)&coord2)
address of arg: 0x7ff7b10183b8
address of arg->x: 0x7ff7b10183b8
address of arg->x: -1783957616
address of arg->y: 0x7ff7b10183bc
address of arg->y: 1074118409

printDoubleCoordAddrAndValue(&coord2)
address of arg: 0x7ff7b10183b8
address of arg->x: 0x7ff7b10183b8
address of arg->x: 2.718280
address of arg->y: 0x7ff7b10183c0
address of arg->y: 3.141590

printDoubleCoordAddrAndValue((struct doubleCoord*)&coord1)
address of arg: 0x7ff7b10183c8
address of arg->x: 0x7ff7b10183c8
address of arg->x: 0.000000
address of arg->y: 0x7ff7b10183d0
address of arg->y: 0.000000

printIntCoordAddrAndValue() で構造体のメンバ変数のアドレスを表示すると、 coord1, coord2 の両方で、構造体のアドレスから 4 bytes 進んでいます。 逆に、 printDoubleCoordAddrAndValue() では、メンバ変数のアドレスは構造体のアドレスから 8 bytes ずつ進んでいます。 図2 は coord1coord2 のメモリ配置のイメージです。

図2. メンバ変数のアドレスの配置イメージ

printIntCoordAddrAndValue() で構造体の各メンバ変数の値を表示すると、 coord12, 3 と初期化した値が表示されたのに対し、 coord2 はそれぞれ 2.71828, 3.14159int にキャストした値 2, 3 にはなりませんでした。 逆に、 printDoubleCoordAddrAndValue() では、 coord2 は初期化時の値 2.718280, 3.141590 が表示されたのに対し、 coord12.000000, 3.000000 とはならず、それぞれ 0.000000 と出力されました。

動作の比較

printIntCoordAddrAndValue() の動作の比較

printIntCoordAddrAndValue() では、メンバ変数 x, y の型がそれぞれ int 型として扱われるので、それぞれの領域が 4 bytes として扱われます。 coord1coord2 を引数として受け取った場合の参照先の比較イメージを図3 に示します。

図3. printIntCoordAddrAndValue() におけるメンバ変数への参照の比較

coord1printIntCoordAddrAndValue() に渡した場合、実際のデータのメンバ変数もサイズが 4 bytes なので、参照先がメンバ変数のアドレスと一致します。 一方、coord2 を渡した場合、実際のデータのメンバ変数のサイズが 8 bytes なのに対し、 printIntCoordAddrAndValue() ではメンバ変数の領域は 4 bytes として扱われるので、参照先とメンバ変数のアドレスが一致しません。

さらに、 coord2浮動小数点型 (正確には倍精度浮動小数点型) なので、整数型とビットの並びが異なります。 coord2 について、 arg->xcoord2.x の前半 4 bytes 分を、 arg->ycoord2.x の後半 4 bytes 分を整数として扱おうとしたので、初期化した値と異なる値として表示されました。

printDoubleCoordAddrAndValue() の動作の比較

printDoubleCoordAddrAndValue() の動作は printIntCoordAddrAndValue() の逆と考えられます。

printDoubleCoordAddrAndValue() では、メンバ変数 x, y の型がそれぞれ double 型として扱われるので、それぞれの領域が 8 bytes として扱われます。 coord1coord2 を引数として受け取った場合の参照先の比較イメージを図4 に示します。

図4. printDoubleCoordAddrAndValue() におけるメンバ変数への参照の比較

coord2 は実際のメンバ変数のサイズがそれぞれ 8 bytes なので、 printDoubleCoordAddrAndValue() でそれぞれ arg->x, arg->y の参照先と実際のメンバ変数のアドレスが一致します。 一方、 coord1 のメンバ変数のサイズはそれぞれ 4 bytes なので、 参照先と実際のメンバ変数のアドレスは一致しません。

加えて、 coord1 について、 arg->y は実際には coord1領域外 を参照しています。 確保されていないアドレス であったり、 他の変数で確保された領域 を参照する可能性があります。 実行例では、 arg->y の値は 0.000000 と出力されましたが、実際には値は不定です。

異なる構造体へのポインタのキャストの実験

型のサイズが合えば、キャストするメンバ変数の型が異なる場合でも意図したように動作させられるのではと考えました。 例えば、サイズ 4 bytes の int 型は、サイズ 1byte の char 型 4 つ分とちょうど同じサイズになるはずです。

図5 のように、要素数 4 の char 型の配列をメンバに持つ構造体 struct char4 と、 int 型の変数をメンバに持つ構造体 struct integer を考えます。 どちらも value のメモリサイズは 4 bytes となります。

図5. 構造体のメンバ変数のサイズのイメージ

この 2 つの構造体に対して、次のような処理を実行してみます。

  1. value に格納されている値を 1 byte ごとの char 型として表示
  2. value に格納されている値を 4 bytes の int 型として表示

実装例

1 と 2 の処理をそれぞれ実装したプログラムを以下に示します。

#include <stdio.h>

// char 型 4 つで 4 bytes のメンバ変数を持つ構造体を定義
struct char4 {
  char value[4];
};

// int 型 1 つで 4 bytes のメンバ変数を持つ構造体を定義
struct integer {
  int value;
};

// それぞれの value の要素の文字と文字コードの 16 進数表記を表示
void printChar4(struct char4 *arg)
{
  for (int i = 0; i < 4; i++) {
    char ch = arg->value[i];
    printf("%c: 0x%x\n", ch, ch);
  }
}

// value の値を 16 進数表記で表示
void printInteger(struct integer *arg)
{
  printf("value: 0x%x\n", arg->value);
}

int main(int argc, char **argv)
{
  struct char4 ch4 = { { 'h', 'o', 'g', 'e' } };
  struct integer intg = { 0x686f6765 };

  // それぞれの構造体のアドレスを表示
  printf("address of ch4: %p\n", &ch4);
  printf("address of intg: %p\n", &intg);
  printf("\n");

  // 変数 ch4 のアドレスを printChar4() に渡す
  printf("printChar4(&ch4)\n");
  printChar4(&ch4);
  printf("\n");

  // 変数 intg を struct char4* にキャストして printChar4() に渡す
  printf("printChar4((struct char4*)&intg)\n");
  printChar4((struct char4*)&intg);
  printf("\n");

  // 変数 intg のアドレスを printInteger() に渡す
  printf("printInteger(&intg)\n");
  printInteger(&intg);
  printf("\n");

  // 変数 ch4 を struct integer* にキャストして printInteger() に渡す
  printf("printInteger((struct integer*)&ch4)\n");
  printInteger((struct integer*)&ch4);
  printf("\n");

  return 0;
}

1 の処理は struct char4* 型の引数を受け取る手続き printChar4() として実装します。 構造体 struct char4 のメンバ変数 vaulechar 型の配列なので、各要素にアクセスすることで 1 byte ごとの値を取得できます。 それぞれの要素の文字と 16 進数表記の文字コードの値を表示させています。

2 の処理は struct integer* 型の引数を受け取る手続き printInteger() として実装します。 構造体 struct integer のメンバ変数 valueint 型なので、 value にアクセスすることで 4 bytes の値をひとまとまりとして扱うことができます。

注意

ch4.value を文字列として扱う場合、文字列の終端を表す '\0' も格納する必要があります。 この例では、 ch4.value を文字列としてではなく、 byte 単位で値がどのように扱われるかの確認で利用しているので、初期化時に '\0' を格納していません。

実行結果

実行結果は以下の通りです。

address of ch4: 0x7ff7bde8e3d8
address of intg: 0x7ff7bde8e3d0

printChar4(&ch4)
h: 0x68
o: 0x6f
g: 0x67
e: 0x65

printChar4((struct char4*)&intg)
e: 0x65
g: 0x67
o: 0x6f
h: 0x68

printInteger(&intg)
value: 0x686f6765

printInteger((struct integer*)&ch4)
value: 0x65676f68

1 の処理について、 printChar4(&ch4) では h, o, g, e の順に表示されているのに対し、 printChar4((struct char4*)&intg) では e, g, o, h と逆順に出力されました。 逆に 2 の処理では、 printInteger(&intg) は代入した値 0x686f6765 と表示されたのに対し、 printInteger((struct integer*)&ch4) では 0x65676f68 と byte 単位で逆順の値が表示されました。

これは、筆者の動作環境では、バイトーオーダーが トルエンディアン になっているからです。 図6 は、それぞれの構造体型の変数 ch4intg に格納されるデータのイメージを byte 単位で表したものです。 変数 intg のメンバ value のサイズは 4 bytes なので、リトルエンディアンでは value の先頭のアドレスから byte 単位で逆順にデータが格納されます。

図6. 構造体のメンバ変数のメモリと格納されている値のイメージ

printChar4() では、 value の先頭の 1 byte から順に表示しているため、 ch4 は意図した順に表示されます。 一方、 intg は 4 bytes のデータをリトルエンディアンで格納するので、 1 byte ごとに表示すると、逆順に表示されます。

printInteger() は逆に、 intg を 4 bytes 単位でリトルエンディアンで扱うと意図した通りに表示されるのに対し、 ch4value を 4 bytes 分リトルエンディアンで扱うとバイトーオーダーが逆転します。

まとめ

ポインタはメモリのアドレスを表し、そのアドレスから型のサイズ分をデータの格納されている領域としてみなせます。 例えば、 int* であれば、基準のアドレスから 4 bytes 分が領域となります。

構造体へのポインタも同じように考えられます。 メンバ変数の型が一致 していれば、異なる構造体でもポインタにキャストすることで 多相性 のように扱うことができます。

5 年以上前の疑問が、前回の記事をきっかけに解決するとは思っていませんでした。 ポインタへの理解が深まったという実感とともに、改めてポインタはシンプルだが難しいと感じました。

参考文献

C のポインタへのキャストをちょっと理解する話

マルチスレッドのプログラムの書き方を勉強するために、 C の pthreadsライブラリを使ったマルチスレッドプログラミングの参考書のサンプルコードを写経して動作を確認して勉強していました。 スレッドを作成する際に、 pthread_create() という関数を利用するのですが、サンプルコードで少し奇妙に感じる書き方をしていました。

pthread_create(&thread, NULL, threadFunc, (void*)1);

(void*)1 が何を意味しているか全然わからん!!!

何をやっているのか分からなかったので、 (void*)1 と書く代わりに、 int* の変数を使って書いていました。 少し日をおいてから、ふとしたきっかけから解決したので、自分の備忘録を兼ねてまとめておこうと思います。

サンプルコードの疑問点

冒頭でも挙げたように、 (void*)1 がどのように動くのか、何を意味しているのかがわかりませんでした。 スレッド作成時に実行する関数の引数に、 int 型の値を渡したいが、 pthread_create() のインタフェースが void* だからキャストしているのかなと思いました。

しかし、 1整数型 であるのに対し、 void* へのキャストは ポインタ型 に変換しています。 なぜこのキャストで動くのか疑問でした。 (疑問点1)

また、関数側では、受け取った引数を void* から int にキャストしていました。 疑問点 1 と真逆のキャストですが、ポインタから整数型へのキャストでどのように動作するのか疑問でした。 (疑問点2)

#include <stdio.h>
#include <pthread.h>

void* threadFunc(void*);

int main(int argc, char **argv)
{
  pthread_t thread;
  // 疑問点1: (void*)1 で通るのなんで?
  pthread_create(&thread, NULL, threadFunc, (void*)1);
  pthread_join(thread, NULL);
  return 0;
}

void* threadFunc(void* arg)
{
  // 疑問点2: void* を int にキャスト?
  int n = (int)arg;
  printf("n: %d\n", n);
  return NULL;
}

ポインタのキャストの誤解

疑問点2 について、 void* はポインタだから、 int* に変換した上で参照先の値を取り出さないといけないのではないかと考えました。 自分なりに考えて、疑問点2 のコード箇所を以下のように書いていました。

int n = *(int*)arg;

まず (int*)argint へのポインタ型に変換し、 arg の参照先の値を参照するために * 演算子を使う必要があると考えていました。 コンパイルも問題なく通ったので、実行してみると Segumentation fault でコケました。

筆者のイメージでは、上記のコードは、図1 のように動作していると思いました。

f:id:sierra-kilo:20220412172721p:plain
図1. ポインタのキャストによる動作イメージの誤解

疑問点1 のコード部分で整数リテラル 1 がどこかしらのメモリ (図1 中の 0xDEADBEEF) に割り当てられ、それを void* にキャストし、疑問点2 の関数 threadFunc() の引数 arg が別のアドレス (図1 中の 0xCAFEBABE) が割り当てられ、その値に参照元のアドレス 0xDEADBEEF が代入されると思っていました。

解決方法の模索とポインタの理解

明示的に領域を確保

threadFunc() 側のキャストを書き換えただけなので、 pthread_create() の第 4 引数も修正しないといけないのかなと考えました。 整数リテラル 1void* でキャストする代わりに、 int* 型の変数を用意してから、その変数を void* にキャストして引数に渡してみることにしました。 疑問点1 の部分を以下のように書き換えました。

// int* 型の変数 arg を宣言して malloc() でメモリ領域を確保
int* value = malloc(sizeof(int));
// 値 1 を arg の参照先に代入
*value = 1;
// arg を void* にキャストして pthread_create() の第 4 引数に指定
pthread_create(&thread, NULL, threadFunc, (void*)value);

一旦 value という int* 型の変数に、 malloc() で領域を確保し、 *value = 1 で実際に threadFunc に渡すための値 1 を代入します。 valueint* なので、 pthread_create() の引数で void* にキャストしています。

こちらは問題なく動作しました。

まず、 malloc() で明示的にメモリ領域 (図2 中 0xDEADBEEF) を確保し、 変数 value の値に、先程確保したアドレス 0xDEADBEEF を指定します。 関数 threadFunc() の引数 arg の値には、main() の変数 value の参照先のアドレス 0xDEADBEEF が格納されます。 argvoid* 型なので、 int* にキャストし、参照先 0xDEADBEEF に格納されている値を取り出すために * 演算子を用いることで、欲しかった値 1 を無事取り出せました。

f:id:sierra-kilo:20220412201351p:plain
図2. ポインタ変数を経由した際の動作イメージ

変数のアドレスの確認

変数を用意し、領域を明示的に確保すると問題なく動作するのに、整数リテラルvoid* でキャストするとうまく動作しないのはなぜだろうと疑問に思いました。 そこで、 (void*)1 とキャストした際に、 threadFunc() の引数 arg の参照先がどうなるのか確認してみることにしました。

以下のようなコードを書いて、動作を確認してみることにしました。

#include <stdio.h>

// void* 型の引数を 1 つ受け取る手続き func() を宣言
void func(void*);

int main(int argc, char **argv)
{
  // func() の引数に 整数リテラル 1 を void* にキャストして渡す
  func((void*)1);
  return 0;
}

void func(void* arg)
{
  // arg のアドレスを画面に出力して確認する
  printf("arg address: %p\n", arg);
}

コードをコンパイルして実行すると、以下の実行結果が得られました。 (行頭の $ はプロンプト)

$ ./a.out 
arg address: 0x1
$ 

この実行結果から、 arg の参照先は 0x01 であることがわかります。 つまり、図1 のように、 1 という整数リテラルの値がどこかしらのメモリに割り当てられて格納されるのではなく、 void* でキャストすることで、図3 のように参照先が 1, つまり 0x01 のアドレスを参照するという意味だったのです。 「ポインタのキャストの誤解」のセクションで修正したプログラムが Segumentation fault を起こしたのは、 0x01 という、プログラム上で確保されていない領域にアクセスしようとしたからです。

f:id:sierra-kilo:20220413164356p:plain
図3. 実際のメモリの動作イメージ

一方で、元のサンプルコードのように、 void* から int にキャストする場合は、 0x01 というアドレスの値を、 1 という整数にキャストしているので、意図した通りに値 1 を取得できます。

コンパイラの警告の内容

ポインタがどのように動作しているかを理解して、サンプルコードが意図した通りに動作するのはなぜかという疑問は解決できました。 しかし、コンパイラは以下のような warning を吐いていました。

warning: cast to smaller integer type 'int' from 'void *' [-Wvoid-pointer-to-int-cast]

実行ファイルは生成され、ちゃんと動作もするのですが、どうにも warning が出ているのが気持ち悪いと感じます。 警告メッセージは、小さいサイズの型にキャストしていると言っているようです。

intvoid* のサイズの比較

それぞれ intvoid* のサイズを比較するために、以下のコードを書いて、実行してみます。

#include <stdio.h>

int main(int argc, char **argv)
{
  // int のサイズ
  printf("sizeof(int): %lu\n", sizeof(int));
  // void* のサイズ
  printf("sizeof(void*): %lu\n", sizeof(void*));

  return 0;
}

実行結果は以下の通りでした。 (行頭の $ はプロンプト)

$ ./a.out 
sizeof(int): 4
sizeof(void*): 8
$ 

筆者の環境では、 void* の型サイズが 8 なのに対して、 int の型サイズが 4 であることがわかりました。 このサイズの違いが warning になっている原因のようです。

ちなみに、動作確認した環境では long の型サイズが 8 だったので、 intlong に書き換えてコンパイルしてみると、この warning は消えました。

なお、以下の環境で動作確認しました。

intvoid* などのサイズは 環境に依存 するので、上記のコードの 実行結果が異なる場合があります

まとめ

C で int の値をポインタ型へキャストすると、 int の値が参照先のアドレスとして扱われます。 逆にポインタ型を int などの整数型にキャストすると、アドレスの値が整数値として扱われます。 int 以外でも、 longchar でも同様のことができるはずです。

void* から int にキャストするような場合、 int とポインタ型のサイズが異なる場合があるので、コンパイル時に警告が出る可能性があります。 それに、コードの意図が若干わかりづらくなる可能性もあるので、筆者は「明示的に領域を確保」のセクションで書いたコード例のように、ポインタ型の変数を用意し、領域を確保した上で、値を代入して渡す方がより分かりやすいのではないかと考えます。

ポインタの理解が浅いので、「C言語ポインタ完全制覇1をもう一度読み直してみようと思います。 (特に関数ポインタの部分が理解できていないので...)

参考文献

DojoCon Japan 2019 参加レポート Part 3

DojoCon Japan 2019 参加レポート Part 2 に引き続き、DojoCon Japan 2019の参加レポートを書いていきます。参加から半年も経ってしまい、今更感が拭えないのですが、気にせず書いていこうと思います(笑)

スーパー学生トーク

CoderDojoなどで活躍する学生の三橋 優希氏、野崎 智弘氏、山野 一樹氏、浦添 一氏、村馬 弘一氏(モデレータ)が、リアルタイムで聴講者の質問に答えるトークショーでした。司会もパネリストもスーパー学生が中心に行いました。セッションの様子は こちら から閲覧できます。

概要

このセッションでは、Slidoを利用してリアルタイムにパネリストに質問を投げ、挙がった質問をピックアップして答えるという形式を取っていました。

以下、質問のセクションごとに回答の要約を記載します。

好きなプログラミング言語

  • Ruby
    • 理由は名前が可愛いから
    • 書けるようになりたくて、 Ruby on Rails でプロジェクトを作ったりRuby Kaigi に参加したりして勉強した
  • JavaScript
  • Vue.js と Nuxt.js
  • C#
    • 理由は少し書けるから
  • Scratch
    • 書いていて楽しいから

CoderDojoで大変だったことと楽しかったこと

大変だったこと
  • 基本的に大変だったことはない
    • 強いていえば交通費の面が大変と思ったことはあった
  • CoderDojoに参加するまでScratchを触ったことがなくてどう教えたら良いか悩んだ
    • 自身が高校で習っている最中の三角関数を小学生が扱っていて教えるのに苦戦した
  • Dojoのチャンピオンとして、小学生のニンジャがいうことを聞かなかったり喧嘩したりすることがあって落ち着かせるのが大変
  • 未成年だと行政団体の手続きが大変
    • 対外的な面で大人の同伴が必要
  • 自分よりScratchの分かるニンジャに教えるのが大変
    • 自分なりのコードを教えても違った場面で通じない場合にどうしたら良いか考えるのが難しかった
楽しかったこと
  • わからない箇所をニンジャと一緒に考えて解決できた時に達成感を感じる
  • メンターやニンジャなどDojoに参加している人たちと話すことが楽しい
    • プログラミングなどの共通のジャンルの興味について話せることが楽しい
  • ニンジャの面白い作品を見ることが楽しい
  • 自分と同じ年代でプログラミングをやっている人と繋がれるという点でCoderDojoというコミュニティが良い

プログラミング教室についてどう思っているか

  • 良いと思っている
    • ただしCoderDojoとプログラミング教室は別物という認識は必要
    • プログラミング教室は強制的にプログラミングを勉強する環境なので成長度は高い
    • CoderDojoは自主的にやる分楽しんでできる
  • 教室とCoderDojoのどちらが良いというのはない
    • プログラミング教室に通いたかったが月謝が高いからだめと言われた経験がある
    • 子供達が無料でプログラミングを学べるCoderDojoというコミュニティが良いと感じた
      • ボランティアとして活動する人も様々で色々な人たちと交流ができて世界が広がった
    • CoderDojoのようなコミュニティの発展を望む
  • 本格的に学ぶ際にプログラミング教室は良いと思う
    • CoderDojoはプログラミング教室より敷居が低い
    • CoderDojoでプログラミングをやりたいと思ってからプログラミング教室に通うのもありだと思う
    • CoderDojoはプログラミングに興味をもつための入り口としての役割を果たしている
    • 本格的に学ぶのにプログラミング教室を活用する
  • CoderDojoはプログラミングだけでなく、絵だとかロボットなど色々な分野のことができる
    • プログラミング教室でも色々なものが経験できる場所もある
    • CoderDojoの方が色々な人がいる

イデアはどんな時に浮かぶか

  • 何もしてない時に浮かぶ
  • ふとした思いつきや考えてパッと出てきたもの
  • 物事を深く考えたあとに出てくる
    • イデアは自分が考えたプロセスの結果だと思う
  • 散歩している時
    • 風景を眺めているとふと出てくる

プログラミングの仲間はどう作ったか

  • CoderDojoに参加してからできた
    • CoderDojoに来るまでは身近にはいなかった
  • Scratchのコメント機能からできた
    • 実際にCoderDojoで会える
  • N高等学校
  • 高専で情報系の専攻をしている学生と繋がった
    • 高専に進んだ友人経由

所感

セッション全体が、質問に答えるという形式は非常に面白い試みだと感じました。リアルタイムで聴講者の質問に答えるという、アドリブ力が必要とされる場で、即座に答えられるのが本当に凄いと思います。

聴講者の人数もそこそこいる中、人前で堂々話せる度胸も凄いと思いました。筆者自身は人前に出て話すこと自体が非常に苦手なので、人前でしっかり話せるのが羨ましく感じました。自身も勉強会などで登壇する際に、落ち着いて堂々と発表できるようになりたいものです。

CoderDojoなどを通じて様々な人と交流を深めたり、CoderDojoのチャンピオンとして活動されていたりすることもあり、質問に対する回答も非常にしっかりしていると感じました。どう思っていて、なぜそう思うのか、考えるのかを明確に答えるのは、おそらく大人でも簡単なことではないと思うのですが、彼ら/彼女らはそれがしっかり出来ているように思います。

筆者自身、高校まで大して何も考えずにぼんやりと生きてきたので、しっかりした考えなんて当然持ち合わせていませんでした。自分の高校生時代を振り返ると、如何に彼ら/彼女らが活動的で、信念を持っているかがよく分かります。実は彼ら/彼女ら、人生2週目なんじゃないかな? (笑) いや、自分の過去と比較するのがおこがましいんだ、多分。

実際にSlidoにはたくさんの質問が投げられ、セッションの時間では足りないほどでした。それだけ聴講者も活躍する学生に興味を持っていたといえますね。基本的にはプログラミング関連の話題が多かったように思います。

もし、読者の方々の中で、学生を持ち上げ過ぎ、褒めちぎりすぎと思われる方がいらっしゃれば、ぜひセッションの様子を見ることをお勧めします。セッションの様子は こちら から閲覧できます。大事なことなので2回書きました(笑)

このセッションは、個人的に楽しみにしていたセッションの一つでした。CoderDojoの繋がりで知り合った方2名が登壇するということで、どんな話をするんだろうなぁと楽しみにしていました。楽しみすぎて、たしかDojoCon Japanの1週間前くらいから夜しか寝れませんでした(笑) 念のために書いておきますが、楽しみにしてたのは本当です

不登校の子供達の支援に関する討論

CoderDojo Japanの理事であり、CoderDojo 西宮・梅田のチャンピオンをされている細谷 崇氏による「 凸凹があってもいい、CoderDojoが支える子どもたちの次のステップ 」という題目でのディスカッションでした。

諸事情でセッションの途中から参加したので、参加途中からの内容を覚えている限り書いていきます。結構記憶が怪しいので、補助的に こちら のツイートのスレッドおよび こちら のツイートを参考にさせていただいていますが、 私の記憶違いで間違ったことを書いていたり、整理しきれずに文章が読みづらいものになるかもしれません が、ご容赦ください。

概要

議論の中心は、 不登校 の学生をどう支援していけば良いかでした。学生、保護者、教育現場の関係者など、様々な立場から意見交換をしていました。

実際に学校に行くのがつらくなった学生の方は、中学受験をし、中高一貫の学校に通うことになったのですが、ストレスで学校に行くのがつらくなり、不登校を経験したとのことです。教室ではなく保健室への登校をされていたこともあるそうです。教室への登校に復帰できたこともあり、その際はクラスメイトはごく普通に迎えてくれたとのことで、人間関係によるストレスというよりは、環境の変化による刺激がストレスになったようです。

CoderDojoに足を運ぶようになって、 好きなことをしていい という経験をし、また様々な人との交流によって世界が広がったそうです。現在はCoderDojoの活動に尽力したり、スタートアップのインターンに参加されたりしているとのことです。

昼の定時制学校の教員の方の話では、かつては定時制学校は 夜間に働きながら学ぶためのイメージ でしたが、最近では時間帯は昼で、 不登校の子が通うための役割が大きい とのことです。 環境が変わると学校に通える 子が多いとのことですが、それでもおよそ120人に20人程度は環境が合わずにやめていき、通信制などに移るとのことです。

別の教員の方は、他の子と一緒に学校に来れない子に対しては、時間外で 個別に対応 されているとのことです。しかし、 働き方改革 が提唱されている今、時間外で個別対応などの工夫が難しくなっているとおっしゃられていました。また、個別対応に対して、別の保護者から不平と言われることもあったそうです。

保護者が考えるテンプレートに当て嵌めようとする と、それが ストレス になることも議論として挙がりました。回りの子と違うことに対して保護者の焦り、子供に対して(本人にとっては難しいにも関わらず)回りと合わせるようにさせる言動が大きな負担となるとのことでした。

具体的な事例としては、 文字を読むのは苦手だがタイピングが得意でローマ字は分かる 子がいるらしく、 PC でずっと遊んでいて勉強をサボっているように周りから見られることがあったことが挙げられていました。PCは得意なようで、 PCの分解や組み立て を教えることで内部構造を学んだりしていたそうです。

所感

当事者や関係者の世界の見え方を知る良い機会となったと感じました。今まで身近に不登校を経験した人がいた記憶がなく、どういった経緯で不登校になったり、どのように感じているかを知ることもありませんでした。それ以前に、今までしっかり気に留めたこともなかったような気がします。おそらく、大半の人も同様なのではないでしょうか。

当事者や関係者でないと分からない 部分も大きいのではないかと思います。当事者や関係者以外の第三者不登校の実際について知る機会があれば、もしかしたら支援について理解が進むきっかけになるかもしれないと考えますが、どのように第三者が知る機会を得るか、どの程度理解を得られるかについて議論の余地があるかもしれません。

不登校に関して、当事者だけでなく 回りの環境 についても議論が必要だと思いました。特に、 出来ないのは努力が足りない/サボっている回りと同じでないといけない などの認識は、家庭や学校など、 周辺の環境によるところ が大きいと考えています。 世間体常識 に囚われていると言えるかもしれません。これらの認識は いきなり変えることは難しい ので、どうやって 徐々に変えるのか(あるいは変えないのか) を議論し、教育支援をしていくかを考える必要があると思います。

一般的には簡単に出来ることが出来ない と、 ふざけている ように思われるのかもしれません。出来ないことが理解されないと、本人が決してふざけているわけではないにも関わらず、「サボっている」や「努力が足りない」という評価になってしまうのではないかと考えます。 回りと同じようにすることが容易ではない人がいることが広く知られるようになり、支援が円滑に行われるようになってほしいと思います。

現在の社会では、 学校で教育を受ける ことが当たり前となっていますが、学校以外に 自由に選択できる学校以外の学びの場 が充実すれば、学校が合わない場合でも自分にあった場所を選ぶことができるのではないかと考えます。選択肢が増えることで 興味のあることや得意なことを模索しやすく なり、学校が合わなくても他の居場所も見つけやすくなるような気がします。

筆者自身は、学ぶ場は必ずしも学校でなければならないとは考えておらず、学校以外にも選択肢がある方が良いと思いますが、様々な視点からの議論は必要だと考えます。例えば、学校以外で学ぶ場合、 共通の基礎教育の担保 をどうするかや、小中学校の場合、 義務教育 の面をどう考えるかの議論が必要でしょう。今回のディスカッションのような意見交換をする機会があれば、良い支援方法が生み出せるかもしれないと思います。

余談: 筆者の経験談に基づく考察

筆者の経験的には、うろ覚えながらこれまでの学生生活で、(特に親から) 出来ないことを叱責されていた ように感じます。もしかしたら叱責のつもりはないのかもしれませんが、少なくとも自分の中ではそのように感じていました。以下自身の体験談をいくつか列挙します。なお、この節は他の節とは関連しないので、読み飛ばしていただいても問題ありません。

筆者は手先の器用さを要することが非常に苦手です。大抵の人が簡単にできるようなことが筆者には難しく感じることがあります。例えば、手で開封できるタイプの袋がうまく開けられないことがあったり、細かいものを手や道具を使って組み立てたりバラしたりがうまく出来なかったりしたことがあります。そのことで、「こんなことが出来ないようじゃ将来困るぞ」と叱責された記憶がぼんやりと残っています。 簡単に出来たら苦労してない。

非力なことについても、結構色々言われました。少し重い物を持ち上げたりするのに非常に苦労していると、 男のくせに情けない だの言われました。正直、平均的な男性が普段から鍛えることが当たり前のこととは思えず、なぜあれだけ筋力がつくのか、ずっと疑問に思ってきました。 本当になんで? 実は普段から筋トレをするのが当たり前なの?

まだ書きたいことは色々ありますが、段々話題がずれてしまいますし、何よりただの愚痴の記事になってしまうので割愛します。

筆者自身も上記に挙げたように、回りがごく普通にできることが自分にとっては非常に困難に感じることはいくつかありました。筆者自身の努力不足も原因ではあるのですが、 回りと同じように簡単に出来ないことを叱責されるのはつらい と感じていました。決してふざけているわけでもなく、本当に難しく感じるのに叱責されると、自分にとって難しいということを 他人には理解されない と思うようになり、 どうせ頑張っても叱責されるなら、本当に怠けていて叱責される方がマシだ とひねくれた考えを持つようになっていました。

筆者自身はかなり不真面目で適当な性格なので、それがある種の心の安全装置になっていたと思うのですが、回りと同じように出来ないことで強い劣等感を感じて苦しんでいる人々は、非常に 真面目努力家 なのではないかと筆者は考えます。真面目に取り組んで努力しているにも関わらず、回りが簡単に出来るようなことが出来ないと劣等感に苛まれ、精神的な負担がかかるように思います。しかし、視点を変えて考えると、 得意分野 が見つかれば、それに真面目に取り組めると考えられるので、 一般より秀でた能力 を得られ、 自信にも繋がる のではないかと思います。

人によっては得手不得手が大きいこともあります。それは何らかのハンディキャップを抱えていない人であっても、回りが簡単に出来ることだとしても難しく感じることがあります。出来ないことを叱責するのではなく、 「凸凹があってもいい」 と認め、柔軟に支援が出来るような社会づくりに少しでも貢献できるようになりたいものです。

まとめ

スーパー学生トークでは、CoderDojoなどの活動に精力的に取り組んでいる学生の皆さんの考えに触れることができ、非常に貴重な機会でした。Slidoを用いてリアルタイムに聴講者の質問に答えるという、アドリブ力の要求される場で即座に回答していることが非常に凄いと感じました。聴講者も彼ら/彼女らの考えについて興味を持つ人が多かったようで、Slidoにはセッション時間だけでは答えきれないほどの質問が挙がっていました。

比較するのもおこがましいですが、筆者が同じ年齢の時を振り返ると、これといった活動もしていなければ、しっかりした考えも持っておらず、ぼんやりと生きてきたので、彼ら/彼女らが非常に輝いて見えました。積極的に活動する学生に対して、将来的に何らかの支援が出来たらいいなと思います。

不登校の子供達の支援についての議論では、学生や保護者、教育関係者などの様々な立場から経験に基づいた意見交換がなされました。様々な場所で支援の工夫などが考えられていることを知る良いきっかけとなりました。また、これまで不登校が身近でない自分にとは全く違った世界の見え方があるということを実感させられました。

世界の見え方が違う分、実際に不登校が身近でなかった自分が直接的に有益な支援することは難しそうですが、一方で回りが簡単に出来ることが自分にとっては難しく、なかなかそれを理解してもらえないという経験はしているので、間接的になんらかの形で貢献する方法を考える余地はあるかもしれません。幸いにも、筆者がメンターとして参加しているCoderDojo 西宮・梅田には様々な方が参加されており、交流を持たせていただいているので、色々な話を聞いて知見や考えの幅を広げられそうです。インプットだけでなく、ちゃんと自分の考えもアウトプットして、様々な視点からレビューをいただいて、考えを洗練しつつ、どのような形でなら小さくても貢献できるか模索していけたら良いなと思います。

おわりに

DojoCon Japan 2019の開催から約半年かけて、参加レポートをPart1からPart3に分けて執筆してきました。 (期間の半分以上は全く記事執筆してなかったけど) 執筆当初は午前午後に分けて記事を書くつもりでしたが、まさかPart1をKeynoteの概要と所感で埋め尽くすとは予想もしていませんでした(笑)個人的に内容に非常に共感できるところが多かったです。

1日のイベントでしたが、本当に驚かされることや考えさせられることが多く、良い機会となりました。CoderDojoに関わる方だけでなく、より様々な方に参加していただきたいイベントだと感じました。もし本記事を読んで少しでも興味を持ってもらえたなら、ぜひDojoCon Japanに参加していただければと思います。新型コロナウイルスの影響もあるので、DojoCon Japan 2020が無事開催されるのかは、現時点では分かりませんが、開催が決まればぜひ参加していただければと思います。

DojoCon Japan 2019 参加レポート Part 2

DojoCon Japan 2019 参加レポート Part 1に引き続き、DojoCon Japan 2019の参加レポートを書いていきます。参加から日が経ってしまい、頭から抜けていることもありますが、当日のメモと自分の記憶を頼りに書き起こしていこうと思います。

プログラミングコンテスト プレゼンテーション

Keynote が終わると、コンテスト応募作品のうち、一次審査に通過した作品のプレゼンテーションが最終審査として行われました。今回のコンテストでは、6名の子供の作品が一次審査を通過し、最終審査のプレゼンテーションを行いました。最終審査を通過した子供には、アイルランドで開催されるCoderDojo主催の Coolest Projects International への参加費用が補助されます。

最終審査では、作品を作った子供自身が作品のコンセプトや作成に至った動機などのプレゼンテーションを行いました。また、動作のデモも行い、どのように動作するかの紹介も行っておりました。どの作品も、DojoCon 2019の掲げるテーマ「つぎのSTEP」に沿うものでした。セッションの様子は こちら から閲覧できます。

作品概要

一次審査を通過し、最終審査でプレゼンテーションを行った作品は以下の6作品です。

  1. パパふとらないでねー

    父親の肥満を心配した子供が、つまみ食いなどの防止のために作成した作品です。Micro:bit のを冷蔵庫に取り付け開閉をセンサで感知してScratchの画面にメッセージを表示します。表示されるメッセージは朝、昼、夜でそれぞれ3種類あるとのことです。お父さん、ダイエット頑張れ!w

  2. らん♪RUNランニング

    運動会のリレーの選手に選出されなかった子供が、来年の運動会のリレーの選手として選出されるために、自身でトレーニング管理ツールを作成しました。既に公園などでトレーニングはしているものの、雨天時は外でトレーニングが出来ないので、家で楽しくトレーニングを行うためにトレーニング管理ツールを作成したとのことでした。Micro:bitで体の動きをセンサで取得し、動いた分だけおとぎ話の世界のキャラクターが動かせるというものでした。

  3. 未来の月面調査ロボット

    宇宙探査に興味を持つ子供が、宇宙兄弟の世界を再現して作成した作品です。地球から国際宇宙ステーション経由で月面のロボットに信号を送り、操縦するというものでした。デモンストレーションでは、地球側のコントローラ、信号の中継役の国際宇宙ステーション、月面探査を行うロボットをそれぞれ用意し、宇宙ステーションを経由してロボットを操作していました。

  4. LOST

    色や動作などを失ったScratchの世界のキャラクターが、失ったプログラムの断片を集めることで、徐々に失ったものを取り戻していくというコンセプトの作品です。ゲーム自体が失ったパーツを取り戻すことで徐々に成長していくさまを表しているとのことです。

  5. 新感覚パズルゲーム コンビ!

    2人プレイで交互に1マスずつ進みながらゴールを目指すというゲームの作品です。このゲームはどちらが先にゴールに着くかを競うゲームではなく、互いに協力し、移動したマスの効果を有効活用してゴールを目指すというゲームです。1人でプレイする分には簡単でも、2人プレイでクリアするためには、お互いの協力プレイが重要となるようです。

  6. AI Trash Can

    AIにゴミの種別を判定させ、その種別にあったゴミ箱の蓋を開くシステムの作品です。昨今ゴミを分別し、資源の再利用や再使用が謳われていますが、そのためには人間が自身でゴミの種類をきちんとしなければなりません。AIによって分別を自動で行ってくれれば、人間が自身でゴミの分別を行う手間が省けそうです。

一次審査通過作品については、DojoCon 2019のお知らせページに作者による概要も掲載されています。

所感

お世辞抜きに、本当にレベルの高い作品ばかりでした。プレゼンテーションを聞く前は、どんな感じで発表するんだろうと、軽い興味のレベル(かなり上から目線)でしたが、実際にプレゼンテーションを聞いたらレベルの高さに驚愕させられました。単純に子供の無邪気さが面白いというだけでなく、作品がしっかりテーマを持っているところに、レベルの高さがあったように思います。トップバッターの子の発表が非常に面白く、その後の子供達の発表、プレッシャーだろうなぁとか思っていましたが、決してそのような感じではなく、自分の作ったものを、自分の発表したいように発表していたので、どの発表も楽しく聞けました。特に、 身近な問題を見つけてくる着眼点 と、その問題を解決するソリューションの発想力 が面白く感じました。

今回の発表では、子供自身の身近な問題を見つけ、それに対するソリューションを考え、プログラミングして実現するといった取り組みがしっかり出来ていることに感動しました。意外と大人でも身近な問題を見つけ、解決手段を考えることは難しいのではないかと思います。大人になっていくにつれて常識に縛られていくので、「そういうものだ」と思うことが多くなると、身近な問題として見つけることが困難になるように感じます。

杞憂かもしれませんが、あえて1つ 個人的に思う 不安な要素を挙げるとしたら、コンテストに出場した子供達が、将来的に 自分のやりたいことのためでなく、回りの大人達の顔色を窺って行動するようになってしまわないか 、ということです。規模が大きい分、今後の人生において、本当に自分のやりたいことではなく、回りの大人達の機嫌を窺うことに注力してしまわないかと思う面が私の中にあるのかもしれません。

子供達にとって、回りの大人達というものは、おそらく大人達が思っている以上に大きい存在だと思います。おそらく大半の子供達にとって、 親や学校の先生の言うことは絶対的 で、不満があっても逆らえないことが多いのではないでしょうか。特に年齢が幼いほど、大人の言うことは絶対に正しいと思うのではないでしょうか。少なくとも、自分が子供の頃はそのように感じていました。 (正直、高校まで自分がどのような感じだったか、だいぶ忘れてしまいましたが...)

今回のコンテストの最終審査を受けた子供達にとって、この経験は少なからず影響を与えるでしょう。その影響が、さらに自分のやりたいことを追究する原動力になってくれることを切に願います。

CoderDojo 豊橋と小中高大連携

豊橋創造大学教授の今井 正文氏による「 学生プロジェクト「CoderDojo豊橋」と小中高大連携 」という題目の発表でした。セッションの様子は こちら から閲覧できます。

今井氏のゼミプロジェクトでは、2020年度からの小学校でのプログラミング教育必修化に先駆け、2016年度からHour of Code 豊橋やCoderDojo豊橋を開催し、小中高生がプログラミングを学ぶ機会を提供しており、子供のプログラミング学習に貢献されています。

学校でプログラミング教育を行う際に、USBの使用が禁止されているような場合には、PCにインストールを行わない Hour of CodeMicro:bit の方が適しているとのことでした。また、教育の現場に取り入れるためには、教育委員会で議論する必要がありますが、教材などの実績を示す必要があります。例えば、Hour of Code とは、アメリカの非営利団体 Code.org が提案するプログラミング教育活動で、 1時間 でコンピュータ・サイエンスを学ぶチュートリアルが用意されています。ただし、教材費用の問題もあり、教育委員会だけ通れば良いというわけでなく、公聴会もクリアしなければならず、学校でのプログラミング教育の提案も簡単ではないようです。

大学の活動の一環として子供にプログラミングを教える際に、教える側の人はプログラミングに詳しい人より、そこまで詳しくない人の方が子供達に受けが良いらしいです。ゼミ生が子供達にプログラミングを教える際にも、プログラミングに詳しい人より、軽いノリの人の方が子供に受けが良かったらしく、教えることの難しさを考えさせられました。

プログラミング教育の制度と理論

高校で情報科の非常勤講師を勤められている太田 剛氏による「 メンターのためのプログラミング教育の制度と理論 」という題目の発表でした。セッションの様子は こちら から閲覧できます。

太田氏はCoderDojo市川真間のチャンピオンとしてCoderDojoの活動に寄与されています。

2016年4月より、政府が第4次産業革命やSociety 5.0に対応した人材の育成を掲げ、プログラミング教育の導入を決定しました。現在、ビッグデータの分析やAIの活用への取り組みが注目されています。マイケル・A・オズボーン氏による「雇用の未来」という著書では、AI時代には現在存在している仕事のおよそ半分がAIに取って置き換えられることが記されています。この内容が一人歩きしてしまっていると述べられていました。

2020年から、生徒の主体的な学びが求められるようになっています。しかし、先生が主導で生徒に主体的な学びを求めるという矛盾が発生しているとのことです。従来の教育モデルでは、先生は主に授業中に頑張って一斉授業を行ってきました。これからは授業中は生徒主導で互いに学び合いのモデルになっていくとのことです。先生の役割も、授業中は生徒のアクティブラーニングの補助をし、授業前の準備と授業後の評価をメインに頑張るモデルに変わっていくようです。

小学校でプログラミング教育が始まるにあたり、プログラミング教育のあり方が議論されています。プログラミング教育ということで、コーディングを教えるというイメージがありますが、 プログラミング的思考 を育てることが目的であり、コーディングを覚えることが目的ではありません。しかし、コーディングを覚えることが目的でないということが、コンピュータを使う必要がないと誤って解釈されていることもあり、アンプラグド問題と言われているようです。

学校などで目標とする領域と、なりたいモデル、つまり成熟しつつある領域には差があり、その差は最近接発達領域(ZPD:Zone of Proximal Development)と呼ばれるようです。CoderDojoはZPDを支援する役割を果たすと述べられていました。CoderDojoでは、みんなで考え作っていく場で、すごい子に憧れる場です。メンターは子供のプログラミングを補助する役割で、従来の先生の教育モデルとは異なり、自発的な学びを支援します。子供が主体的に学ぶ場を提供する役割が、今後CoderDojoだけでなく、学校にも求められそうです。そして、CoderDojoに求められる役割も変化していくのかもしれませんね。

まとめ

コンテストの最終審査では、子供達がハイレベルな発表をしていたことに驚かされました。どのような動機で、どのようなテーマで、何を作ったかを、大人に用意してもらった台詞ではなく、自分の言葉でしっかり発表しているように見受けられました。おそらく、大人であっても、前に立って自分の言葉で発表するといったことは、決して簡単なことではないと思われるので、楽しそうに発表している姿はうらやましく感じました。

自分の身近な問題を見つけ、解決のアプローチを考え、実現する ということを子供達が自身で実行出来ていることにも非常に驚かされました。身近な問題を見つけること自体が決して簡単なことではないので、着眼点に驚かされ、さらに解決策を考える発想力にも驚かされました。私自身は、子供の頃も大して身近な問題を見つける着眼点も、問題を解決する柔軟な発想力も持ち合わせていなかったので、どのように面白い着眼点や発想力を持てるのか興味がわきました。

午前中のセッションは、大学の活動の一環としての小中高との連携に関する活動の概要と、プログラミング教育の制度と理論について聴講しました。2020年から小学校でプログラミング教育が必修化となることもあり、プログラミング教育に関心がもたれていますが、教育の現場でどのように進めていくかはまだ試行錯誤をして、ノウハウを蓄積する必要がありそうだと感じました。

国としては、コーディングを教えることが目的ではなく、 プログラミング的思考 を育むことが目的としていますが、しっかりとした理解や認知が広くされていないのではないかと感じます。小学校でのプログラミング教育必修化が決まってから、習い事の1つとしてプログラミング教室が広く開催されるようになりましたが、おそらく大人は、コーディングを教えることがプログラミング教育だと考えているのではないでしょうか。(私も同様にコーディングを教えることだと思っていました...)

一般的に考えられているプログラミング教育と、国が掲げるプログラミング教育の像に大きな解離があるのではないかと思います。プログラミング教育を通じて達成したい目標は何か、どのような手段で達成するかをしっかり理解し、さらに周知する必要がありそうです。


Part 3 に続きます。今回で午前の部が終わりました。非常に内容の濃い午前の部でした。次回で午後の部を書き切ってしまいたいと思いますが、記事の分量で調整予定です。

謝辞 (2020/2/7 追記)

各セッションの動画がYouTubeに公開されたことを 安川要平 様より教えていただきましたので、それぞれのセッションに動画へのリンクを追記しました。この場をお借りして御礼申し上げます。