2022年03月19日 | 更新。 |
デフォルト(defalut)は、コンピュータ用語としては、ユーザーが明示的に設定しない場合に選択される設定を意味します。デフォルトは、初期設定と呼ぶ事もあります。ハードウェアに関しては、デフォルトは、工場出荷時設定と呼ぶ事もあります。
また、各設定項目において、初期設定により設定された値の事をデフォルト値といいます。デフォルト値は、規定値や初期設定値と呼ぶ事もあります。
デフォルトは、デフォールト、ディフォルト、あるいはディフォールトと表記される場合があります。
コンピュータ以外の分野でデフォルトという言葉が使われる場合は、怠慢、不参加、棄権、債務不履行等の意味になります。
このページでは、コンピュータ用語としてのデフォルトについて解説します。
例えば、
「通信速度を明示的に設定しない場合は、暗黙的に9600bpsに設定される」
という事を、デフォルトという用語を使って表現すると、
「通信速度はデフォルトで9600bpsだ」
あるいは
「通信速度のデフォルト値は9600bpsだ」
となります。
1番目の例に示したように、「デフォルトで」という表現は、副詞的に使われます。英語の表現では、by defalutという副詞句(「規定では」という意味)に相当します。(例:「スタックメモリの予約容量は、デフォルトで8kBだ」=「スタックメモリの予約容量を明示的に指定しない場合は、8kBに設定される」)
また、「デフォルトの」という表現は、形容詞的に使われます。英語のdefalutには、名詞だけでなく、形容詞の用法(「他に指定のない場合の」という意味)もありますので、それに相当します。(例:「デフォルトの通信速度でも十分に速く感じる」=「初期設定の通信速度のままでも十分に速く感じる」)
この章では、各種設定においてデフォルト値が使われる理由について、分かりやすく説明します。
ソフトウェア等の設定項目が多い場合、ユーザーが全ての項目を設定するのは手間が掛かります。そこで、多くのユーザーが使う設定値がある設定項目には、そのよく使われる設定値をデフォルト値として決めておくと、ユーザーは、デフォルト値ではない設定項目だけを設定する事で設定を完了でき、手間が省けます。
この事を説明するために、たとえ話として、ある食堂でラーメン定食を頼む事を考えます。このラーメン定食は、ラーメンが一品と、御飯が付いています。
ラーメンは、塩ラーメン、味噌ラーメン、醤油ラーメン、白湯ラーメンの中から選べます。
麺の固さは、柔らかめ、普通、固めの中から選べます。
ニンニクは、入れるか、入れないかを選べます。
ねぎも、入れるか、入れないかを選べます。
御飯は、白飯、炒飯、天津飯の中から選べます。
ラーメン定食は色々と選べる要素が多いので、それを頼む客が、注文伝票にどの様なラーメン定食を頼むかを、書き込まなければならないものとします。
図1の様な注文伝票だったとすると、例えば白湯ラーメンで、普通の固さの麺で、ニンニクは入れて、ねぎは入れないで、白飯を付けるラーメン定食を1つ注文するには、図2の様に、6つの〇を書かねばなりません。
しかし、図3に示す様に、各項目に太字で書かれた選択肢があり、丸を書かないと太字の選択肢が選ばれた事になる注文伝票なら、図4に示す様に、2つの〇を書くだけで、同じ注文ができます。
図3の注文伝票では、各項目で、選択肢の中の1つが太字で書いてあります。太字以外の選択肢を選択する場合は、〇を書く必要がありますが、太字の選択肢を選択する場合は、〇を書いてもいいですし、省略しても構いません。 (例えば、個数の欄に〇を書かないと、1が太字で書いてあるので、1つ注文するものと解釈されます)
この例に示した様に、明示的な選択(この場合は丸を書く事)を省略した場合に選ばれる選択肢(この場合は太字で書かれた選択肢)が、デフォルト値です。
多くのユーザー(この場合はラーメン屋の客)が選択する選択肢をデフォルト値に指定しておく事で、多くのユーザーが、明示的に選択する手間を省けます。(この場合は、〇を書く手間が省けます)
このページの最初で、デフォルトが初期設定とも呼ばれる事を説明しましたが、図3のの注文伝票の場合は、「個数は1個、ラーメンの種類は塩ラーメン、…」とあらかじめ仮に決まっており、その仮の決定とは違う部分だけ、客が〇を付けて明示的に上書きする」という説明をすれば、初期設定という言葉がしっくりくるでしょうか。
デフォルト値には、ユーザーがうっかりと設定し忘れた項目が発生するのを防ぎ、設定のエラーを防ぐという意味もあります。
図1の様に、デフォルト値が設定されていない注文伝票を使う場合、客が麺の固さの指定を忘れると、図5に示す様な、麺の固さが未選択の注文伝票ができ上がり、無効な注文となってしまいます。
図3に示した、選択肢にデフォルト値が決められている注文伝票だと、麺の固さを指定し忘れると、自動的に普通の固さになります。つまり、デフォルト値が設定されている事により、設定項目の指定のし忘れにより設定(この場合は注文)が無効になるのを、防げることが分かります。
仮に客が柔らかめの麺を望んでいた場合、デフォルト値のある注文伝票では、麺の固さの指定し忘れにより、望みと違う定食が出てくる事になります。この様な事態を防ぐためには、デフォルト値が設定されていない方がいいとも考えられます。
しかしデフォルト値は、多くの場合、間違って選んでしまっても悪影響の少ない、無難な選択肢に決められています。
図3の注文伝票では、普通が麺の固さのデフォルト値です。多くの客が普通の固さの麺を注文するでしょうし、仮に柔らかめの麺を好む客や、固めの麺を好む客が、〇の記入を忘れ、デフォルトの普通の固さの麺を頼んでしまっても、好みと反対の固さの麺が出てくるよりはましでしょう。
ラーメンの麺の固さの場合は、普通が無難な選択だといえますが、例えば電源装置の出力電圧の設定の場合は、低めの電圧が無難な選択になります。デフォルト値が高い電圧になっていると、電源装置につながっている回路がいきなり故障するかも知れません。一方で、出力電圧が低すぎる場合は、電源装置につながっている回路が正常に動作しないかも知れませんが、壊れてしまう事はないでしょう。よって、デフォルト値を低い電圧に設定すれば、つながっている回路が壊れてしまうという最悪の事態を回避できるのです。
この様に、デフォルト値は、手間を省きつつ、かつ最悪の事態を回避しながら、無効な設定を防いでいるのです。
ラーメン定食の場合はたった6つの設定項目しかありませんが、複雑なソフトウェアやハードウェアの場合は、設定項目が数百あるいは数千に及ぶ事があります。この様な場合、使い始めるにあたって、全ての設定項目を理解して、全ての項目を設定してから使い始めるとなると、とても時間が掛かります。
設定項目にデフォルト値が設定されている場合は、とりあえずお勧めの設定(=デフォルトの設定)で動作させてみて、具合いが悪い所があれば、資料で調べながら、関係がありそうな項目の設定を変えるという具合に作業を進める事ができます。
ソフトウェアの保守をしていると、アップデートにより機能を追加する事が良くあります。
例えば、リスト1に示す様な、C++の関数を使っている場合を例に考えます。
void inc(int &v)
{
v++; // 変数vの値を1つ増やす
}
このinc関数は、int型の変数を1つ、引数に取る関数で、渡された変数の値を、1だけ増やす働きをします。
例えばリスト2のmain関数では、5行目のinc(i);
で、変数iの値を、初期値の5から1だけ増やして6にしています。
int main(void)
{
int i=5; // int型の変数iを5で初期化
std::cout << i << cout::endl; // iの値を表示して改行(5を表示)
inc(i); // iの値を1つ増やす
std::cout << i << cout::endl; // iの値を表示して改行(6を表示)
return 0;
}
注:リスト2は、main関数だけ抜き出したもので、完全なプログラムではありません。#include <iostream>
を記述しないとstd::coutやstd::endlが使えませんし、リスト1のinc関数の宣言も加えないと、inc関数が使えません。
次に、リスト1のinc関数をアップデートして、リスト3の様に、変数に加える数を指定できる様にすると仮定します。
void inc(int &v, int n=1)
{
v+=n; // 変数vの値をnだけ増やす
}
ここで、新しいinc関数では、2番目の引数nが追加されている事に注意してください。このnが、変数vに加える数になります。
例えば、変数iの値を3だけ増やしたいならinc(i,3);
と記述する事になりますし、変数iの値を1だけ増やしたいなら、inc(i,1);
と記述する事になります。
また、2番目の引数nの宣言部分で、int n=1
と、デフォルト値が1と指定されている事にも注意してください。この指定により、2番目の引数(n)が省略された場合は、2番目の引数が1であると解釈されるようになります。つまり、inc(i);
は、inc(i,1);
と解釈され、変数iの値を1だけ増やす事になるのです。これは、古いinc関数(リスト1)と同じ動作です。
この様に、2番目の引数の初期値を1に設定する事により、リスト3の新しいinc関数は、リスト1の古いinc関数と上位互換性を持つ事になります。 (古いinc関数は、新しいinc関数の下位互換になります) よって、リスト2のmain関数は、inc関数をリスト1の古い物からリスト3の新しいものに差し替えても、以前と同様に動作します。
この例で示したように、ソフトウェアのアップデートにより設定項目が増えた場合、新しく増えた設定項目にデフォルト値を設定し、かつ、デフォルト値で動作させた場合に以前のソフトウェアと同様に動作する様にしておけば、コードの互換性を確保できます。 (古いコードが変更なしに使える様になります)
ソフトウェアやハードウェアの設定において、無効な設定が行なわれた場合に、再設定をユーザーに促すなどのエラー処理が行なえない場合があります。その場合には、有効なある値が設定されたものとして処理を進める事があります。この時の「有効なある値」がデフォルト値です。
例えば、UART(シリアル通信)の通信速度を、ソフトウェアの設定ファイルで行なう事を考えます。通信速度は0や負の数にはなりませんし、正の数であっても、ハードウェアの制約上、上限と下限があります。そこで、通信速度のデフォルト値(例えば9600bps)を決めておき、無効な値を通信速度に設定した場合は、デフォルト値の9600bpsで動作させる事にしておけば、目的の通信速度ではないかもしれませんが、取りあえず、ソフトウェアをエラーを起こさずに動作させる事ができます。
特に組込機器のプログラムでは、エラーメッセージを表示するディスプレイも、設定条件を再入力するキーボードも設置されていない場合が多いので、設定にエラーがあっても、とりあえず機器を動作させる必要がある場合が多くあります。(そうでないと、機器が故障してるのと見分けがつきません) その様な場合に、設定にエラーがあった場合の既定の動作を決めておく事が良くあります。
プログラミング言語において、デフォルト値がどの様に使われているかを説明します。
C++や、他の多くの言語では、関数(あるいは手続き)の引数にデフォルト値が指定できる様になっています。その場合、該当する引数の指定を省略すると、引数にデフォルト値が渡されたものとして処理されます。
例えば、リスト3に示したC++で記述されたinc関数では、2番目の引数(n)のデフォルト値が1に指定されています。この指定により、2番目の引数を省略してinc関数を呼び出すと、2番目の引数は暗黙的に1と解釈され、処理されます。
C言語、C++、C#、PHP、JavaScriptなど多くの言語で、switch文(あるいはswitch~case文)と呼ばれる、多分岐構造を表す文があります。
参考:Pascalのcase文もswitch文と同じ働きをします。Pascalの場合は、switch文のdefalut節に相当するのは、case文のelse節です。
switch文は、式の値によって、処理を振り分ける働きをします。例として、C言語およびC++のswitch文の構文を、リスト4に示します。
switch(制御式) {
case 値1:
文
文
………
break;
case 値2:
文
文
………
break;
………
default:
文
文
………
}
注:リスト4では、バグの原因になりやすいフォールスルーは使わないものとしています。実際のC言語では、あるcase
と次のcase
の間にbrak;
を書かない書き方も許容しています。
制御式は、整数型の式です。この制御式の値により、switch文は処理を分岐します。制御式の値が値1の場合は、case 値1
の次の文から、break;
が表われる直前の文までを実行します。同様に、制御式の値が値2の場合は、case 値2
の次の文から、break;
が現れる直前の文までを実行します。case
はいくつでも書く事ができます。
もし制御式の値がcase
により指定された値(値1、値2、…)のいずれにも等しくない場合は、default:の後の文を実行します。
このswitch文において、defalut節(default
以降の処理)が、デフォルトの分岐処理になります。switch文において、多くの制御式の値において、共通の処理をする場合は、default節に記述します。そして、デフォルトの分岐処理以外の処理をしなければならない制御式の値のみ、case節(case
から次のbreak;
までの処理)を記述する事で、switch文を簡潔に記述できる様になり、また、全ての制御式の値に対して、もれなく処理を記述できるようになります。
例えばリスト5のswitch文は、int型の変数iの値が0の場合は"ZERO"、値が1の場合は"ONE"、値が2の場合は"TWO"、値が0でも1でも2でもない場合は"OTHER"と表示してから改行します。
switch(i) {
case 0:
std::cout << "ZERO" << std::endl; // ZEROと表示して改行
break;
case 1:
std::cout << "ONE" << std::endl; // ONEと表示して改行
break;
case 2:
std::cout << "TWO" << std::endl; // TWOと表示して改行
break;
default:
std::cout << "OTHER" << std::endl; // OTHERと表示して改行
}
いくつかのプログラミング言語では、三項演算子やnull合体演算子が使えます。これらを使うと、代入文で不正な値を代入しようとした時に、代わりにデフォルト値を代入する事が出来ます。主にエラー処理に使われます。
三項演算子を実装しているプログラミング言語では、たいていの場合、式1 ? 式2 : 式3
という書式で三項演算子が実装されています。この式は、式1をブール値(bool型やboolean型の値、真理値)として評価した場合に、それが真(true)なら式2の値を返し、偽(false)なら式3の値を返します。
例えば、(i > 100) ? "BIG" : "SMALL"
なら、変数iの値が100より大きければ"BIG"、100以下なら"SMALL"という文字列を返します。
参考:C言語の場合、比較演算子より三項演算子の方が優先順位は低いため、i > 100 ? "BIG" : "SMALL"
は、(i > 100) ? "BIG" : "SMALL"
と同様に解釈されます。しかしながら、理解しやすくするために、ここではあえてi > 100
を丸括弧でくくって、三項演算子よりも優先して評価される事を示しています。
C言語は三項演算子の使えるプログラミング言語の代表例ですが、C言語で書かれたリスト6の様なプログラムを考えます。
#include <stdio.h>
int main(void){
int i,n;
scanf("%d",&n); // ユーザーが入力した数をnに代入
i = (n >= 0) ? n : 0; // nが0以上の値なら、iにnを代入。nが負の値なら、iに0を代入。0がデフォルト値。
printf("%d\n",i); // iの値を表示
return 0;
}
リスト6は、ユーザーに整数型の変数iの値を代入してもらうプログラムなのですが、iの値は0以上が有効で、負の値は無効だとします。負の値が代入された場合は0が入力されたものとして処理をします。
このプログラムでは、iとnの2つのint型の変数を4行目で宣言しています。nは、ユーザーが入力した値を一旦受け取るための変数です。ユーザーは不正な値(この場合負の値)を入力する可能性があるため、入力された値を直接iに代入せず、nに代入しています。(5行目)
6行目で、nの値が有効(0以上)か無効(負の数)かを判定し、有効ならばiにnの値を代入し、無効ならiに0を代入しています。この6行目で、三項演算子が使われています。(n >= 0) ? n : 0
の最後の0がデフォルト値です。
この様に、代入文において、三項演算子でnの値をチェックし、nの値が無効なら、iにnを代入する代わりに、デフォルト値の0を代入する事で、iの値が無効になる事を防ぐ事ができます。
JavaScript、PHP、あるいはC#等の言語では、null合体演算子と呼ばれる演算子が使えます。
ここでは、JavaScriptを例に、null合体演算子を説明します。
JavaScriptでは、変数がnullやundefinedという値を取る事ができます。
nullは変数の値が存在しない事を意図的に示す値で変数の内容が無効になっている事を表すのによく使われています。
一方で、undefinedは変数が未定義である事を示します。例えば、宣言されたものの一度も値を代入された事のない変数は、値がundefinedになります。
null合体演算子は、nullまたはundefinedの、一般には無効とみなされる値が、変数に代入される事を防ぐ意味で使われる演算子で、リスト7に示す書式を持ちます。
式1 ?? 式2
この演算子は、式1の値がnullでもundefinedでもなければ式1の値を返し、式1の値がnullまたはundefinedの場合は、式2の値を返します。この式2の値がデフォルト値です。
例えばa ?? 0
という式なら、変数aの値がundefinedでもnullでもない場合はaの値を返し、aの値がundefinedかnullの場合は0を返します。この場合は0がデフォルト値です。
変数aに別の変数bの値を代入する場合、単にa = b;
と記述すれば、bの値がnullやundefinedという無効な値の場合、aの値も無効になってしまいますが、例えばa = b ?? 0;
と、null合体演算子とデフォルト値0を使って記述すれば、bの値がnullやundefinedなら、aにはデフォルト値0が代入される様になり、aの値がnullやundefinedといった無効な値になるのが防げます。