Ruby 2.5 で追加される yield_self メソッド

Ruby 2.5 では Object#yield_self というメソッドが追加される予定です。 これは以下のような実装になっています。

class Object
    def yield_self
        yield(self)
    end
end

平たく言うと『ブロックの戻り値を返す #tap』って感じですね。

何が嬉しいのか

この手の『なんか便利そうなメソッド』のユースケースを説明するのが難しいんですが、とりあえず『#tap + break』で任意の戻り値を返したいような場合は #yield_self が利用できるかと。

# break を使って任意の戻り値を返す
# [1, 2, 3].tap { |myself|
#     break myself.map { |it|
#         it + myself.size
#     }
# }
# => [4, 5, 6]

# yield_self だと break は不要
p [1, 2, 3].yield_self { |myself|
    myself.map { |it| it + myself.size }
}
# => [4, 5, 6]

あとは単純にレシーバの値を複数回参照したい場合とかですかね。

p (1..10).select(&:even?).yield_self { |myself|
    myself + myself
}
# => [2, 4, 6, 8, 10, 2, 4, 6, 8, 10]

こっちの方が使う機会は多そう。

参照

node.js で全ての階層のディレクトリを作成する

node.js の Path の mkdirSyncディレクトリを作成する場合、階層のディレクトリが存在しない場合は新しいディレクトリはつくってくれません。

const FS = require("fs-extra");

// hoge, foo, bar というディレクトリは存在しない場合
FS.mkdirSync("./hoge/foo/bar");
// Error: ENOENT: no such file or directory, mkdir './hoge/foo/bar'

fs-extra を使う

こういう風に全ての階層のディレクトリを作って欲しい場合は fs-extra を使うのが手っ取り早いみたいです。

$ npm install fs-extra -g
const FS = require("fs-extra");

// mkdirSync ではなくて mkdirsSync なので注意
FS.mkdirsSync("./hoge/foo/bar");

これでディレクトリがない場合でも全てのディレクトリが作成されます。
また上記の場合は同期処理ですが、非同期処理の mkdirs もあります。

参照

C++17 で追加される std::apply 関数

C++17 で std::apply という関数が新しく追加されます。
これは『タプル型を展開して関数の引数として渡す』という関数になります。

#include <tuple>
#include <iostream>

int
main(){
    auto print = [](auto id, auto name, auto age){
        std::cout
            <<  "id:"   << id
            << " name:" << name
            << " age:"  << age
            << std::endl;
    };
    auto args  = std::make_tuple(42, "homu", 14);

    // print(42, "homu", 14)
    // みたいに渡される
    std::apply(print, args);

    // print(54, "mami", 15)
    std::apply(print, std::make_tuple(54, "mami", 15));
    
    return 0;
}
// output:
// id:42 name:homu age:14
// id:54 name:mami age:15

引数をタプル型で保持しておいて関数の引数として渡したいことは稀によくあるのでこういうヘルパ関数があると捗るる。

参照

lodash を使って JavaScript でオブジェクトのコピーを行う

昨日書いたオブジェクトのコピーですが、lodashというユーティリティライブラリを使うのが手っ取り早そう

// npm install lodash -g
const _ = require("lodash");

const obj = {
    // Object のプロパティ
    name: {
        sei: "yamada",
        mei: "tarou"
    },
    age: 24
};

const other = _.cloneDeep(obj);
other.age = 17;
other.name.mei = "hanako";

console.log(obj.age);
console.log(obj.name.mei);
// output:
// 24
// tarou

これでおっけー。

JavaScript でオブジェクトのコピー

さて、JavaScript ではオブジェクトの値を代入した場合に参照としてコピーされます。

const obj = {
    name: "tarou",
    age: 24
}

// obj を代入する
const other = obj;

// コピーした値を変えると
other.name = "hanako";
other.age  = 17;

// コピー元のオブジェクトの値も変わってしまう
console.log(obj.name);
console.log(obj.age);
// output:
// hanako
// 17

このように参照渡しの場合は元のオブジェクトに対して意図しない変更が行われる可能性があります。

Object.assign を使う

参照はなくて値をコピーしたい場合は Object.assign を使用するのが簡単みたいです。

const obj = {
    name: "tarou",
    age: 24
}


// Object.assign を経由して代入する
const other = Object.assign({}, obj);
// const other = obj;

other.name = "hanako";
other.age  = 17;

// 元のオブジェクトの値はそのまま
console.log(obj.name);
console.log(obj.age);
// output:
// tarou
// 24

これで大丈夫です。

ネスとしたオブジェクトの場合

ただし、プロパティがオブジェクトの場合は、そのプロパティは参照渡しのままなので注意してください。

const obj = {
    // Object のプロパティ
    name: {
        sei: "yamada",
        mei: "tarou"
    },
    age: 24
}

const other = Object.assign({}, obj);
other.age = 17;
// Object のプロパティを書き換えると
other.name.mei = "hanako";

// Object のプロパティが書き換わってしまう
console.log(obj.age);
console.log(obj.name.mei);
// output:
// 24
// hanako

うーん、この。

JavaScript でセミコロンを省略した場合の弊害

JavaScript でセミコロンを付けるべきか否かっていうは割と宗教的な違いがあると思います。
じゃあ、実際セミコロンをつけなかった場合にどういう弊害があるのか、というのを簡単に調べてみました。
その中で気になった記述をいくつかピックアップしてみます。

行頭が ( から始まる

JavaScript の場合、グローバル空間を汚染しないためによう以下のように (function(){}) で囲ってしまうというテクニックが使われます。

(function() {
    const a = 1;
    const b = 2;
    const c = 3;
})();

これ自体は特に問題はないんですが、次のように『この定義の前にセミコロンがない文を置く』とエラーになります。

// TypeError: 42 is not a function
const global = 42
(function() {
})();

これは JavaScript

const global = 42(function() {
})();

という風に解釈してしまうためです。

return 文

こちらは『セミコロンをつけなかった場合の挙動』っていうのとはちょっと違いますが、次のように return 文の後に改行すると意図しない動作になります。

function test(){
    return
        42;
}
test()  // => undefined

上記のコードはちょっと極端な例ですが、例えば {} を記述する際に改行するようなコーディングスタイルであれば注意する必要があります。

function test(){
    return
    {
        name: "homu"
    }
}
test()  // => undefined

所感

基本的にはセミコロンをつけなくても問題なさそうな気はする。
気はするけど思わぬところで嵌りそうな気もするのでセミコロンをつけておくのが無難そう。

参照

C++ でコンストラクタの引数名をメンバ変数名と同じにする

コンストラクタで引数を受け取ってメンバ変数を初期化する場合、

struct X{
    X(int _value) : value(_value){}
    int value;
};

みたいに引数名に _ prefix/suffix をつけているコードをたまに見かけます。
しかし、実は引数名はメンバ変数名と同じでも問題なく動作します。

struct X{
    X(int value) : value(value){}
    int value;
};

X x{42};
std::cout << x.value << std::endl;

これは C++ の規格で保証されている挙動になります。
もし毎回 _ を付けるのが手間であれば _ を省いてしまっても問題ありません。

見解です。