質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

10回答

16638閲覧

モダンな言語で型が後置な理由

sin_250

総合スコア112

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

11グッド

10クリップ

投稿2019/05/11 16:40

編集2019/05/11 16:41

11

10

タイトル通りのシンプルな質問なのですが、調べてみたものの、
しっくりくる回答がなかったため、質問いたします。

C/C++やJava, C#など静的型付け言語のうち比較的レガシーなものは、
変数定義時の型は前置が主流だと思います。

cpp

1int x = 3; 2int add(int x, int y) { 3 return x + y; 4}

しかしながら、TypeScript, Rust, Goなどのモダンな言語では後置を採用していることが多いです。
これだけ揃っていると偶然とは思い難く、何かしらのメリットがあるのだろうと想像します。

一体どんなメリットがあるのか、ご存知でしたらご教示頂けたら幸いです。

TypeScript

1function add(left: number, right: number): number { 2 return left + right; 3}

Go

1type Circle struct { 2 radius float64 3}

Rust

1fn factorial(i: u64) -> u64 { 2 (1..=i).product() 3}

よろしくお願い致します。

bcaa, yuji38kwmt, tatsukich39, miyabi_pudding, 86ps, YouheiSakurai, LouiS0616, Otama_Clever, atata0319👍を押しています
jackjackjack😍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答10

0

ベストアンサー

StackOverflowでも同じような質問をされている方がいます。

回答を大雑把にまとめると、

(1) 型推論のある言語では、型宣言をしなくても問題ない場合がある

TypeScript

1var myNumber = 1 2// 機械はmyNumberをnumberとして評価できる

(2) 必ずしも必要でない記述を右側にもっていくことで、ソースコードを解釈するときの曖昧性を軽減し、パフォーマンスを向上できる

TypeScript

1number var myNumber = 1

上の記述はイメージですが、機械の立場で言うと、numberの後のvarまで到達しないと、変数宣言かどうかわかりません。変数宣言に必ず必要な「var」と「変数名」が左にくれば、パースのパフォーマンスがあがります。また、(回答者によれば、議論のよちはありますが)人間にとっても可読性があがります。

C++などではオプショナルなものも左に書きますが、int* a, b;ではaはポインターですが、bはそうではありません。現在では、C++にもauto x = int{ 4 };のような後置の型の構文があるようで、いくつかの利点があるようです。

投稿2019/05/11 17:24

NozomuIkuta

総合スコア1260

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/12 01:19

ご回答ありがとうございます。申し訳ありません、英語の情報までは調べ切れておりませんでした。 良質なリンクのご紹介ありがとうございます。 確かに型注釈がオプショナルであれば、後ろに持っていくのは道理ですね。 合ったり無かったりするものが先頭にあれば当然人間(の指)にとっても混乱します。 ありがとうございました。
Otama_Clever

2019/05/14 06:24

このような 素朴な疑問(トピ主様のご質問etc.)こそ、 意義がある、と思いました。 小生も、見習いたく存じます。ホント素晴らしい質問です。なぜなら、老若男女スキルを問わず、閲覧されている可能性が高いと推察するから。 質問者さまに感謝です。 (もちろんテラテイル主催者様、回答者さま方にも、感謝します)
guest

0

これらの言語では型が省略可能だからではないでしょうか。

私はTypeScriptやGoはよく知らないので間違っているかもしれませんが、TypeScriptでは関数の引数の型注釈を省略して以下のように書けたと思います。

TypeSciprt

1function add(left, right) { .. }

Rustは関数の引数と戻り値については型を省略できない仕様になっていますが、クロージャなら省略可能です。

rust

1// クロージャで型を省略した場合 2let factorial = |i| (1..=i).product(); 3 4// クロージャで型を明示した場合 5let factorial = |i: u64| -> u64 { (1..=i).product() };

また変数を導入するlet文でも上のfactorial変数のように通常は型注釈は省略されます。しかし明示もできます。

rust

1// factorial変数の型を明示 2let factorial: fn(u64) -> u64 = |i| (1..=i).product();

型注釈が省略できる言語では、後置にすれば、省略してもしなくても引数名や変数名の位置は同じになります。文法に統一感が出るので人間にとって読みやすくなりますし、言語処理系にとっても構文解析がしやすくなるというメリットがあると思います。

投稿2019/05/11 17:25

編集2019/05/11 17:30
tatsuya6502

総合スコア2046

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/12 01:24

おっしゃる通りの内容ですっきり理解できました。 Rustの例文もありがとうございます。 (余談ですがRustに興味を持っているのでフォローさせて頂きました) ご回答ありがとうございました。
guest

0

まず前提から整理すると、C/C++で変数の型を記述する方法は前置ではありません。

c

1#include <stdio.h> 2 3int add(int x, int y) { return x + y; } 4int mul(int x, int y) { return x * y; } 5 6int main(int argc, char **argv) { 7 int (*functions[2])(int, int) = {add ,mul}; 8 9 printf("functions[0](2, 3) = %d\n", functions[0](2, 3)); 10 printf("functions[1](2, 3) = %d\n", functions[1](2, 3)); 11 return 0; 12}

上記のコードで functions は「int型を2つ取ってint型を返す関数へのポインタの配列」です。
このように、元のCの変数宣言の仕様は複雑な型の場合には破綻します。
(これが訓練せずとも一般に読み書きしやすいとは言えないでしょう)

JavaやC#などでは前置を採用し、更にこのような複雑な型をそもそも書かせないようになっていました。
型が複雑になる前にインターフェースにしてしまうことで回避しますが、言語組み込みではないので、どのようにインターフェース化するかを統一しないと汎用性が下がってしまいます。
(近年では公式に java.util.function.Function などができて統一されました)

きちんと関数の配列のようなものを言語仕様レベルでサポートしたい場合、完全に前置にするか後置にすることでこの問題を回避できます。

go

1package main 2 3import "fmt" 4 5func add(x, y int) int { return x + y } 6func mul(x, y int) int { return x * y } 7 8func main() { 9 var functions [2]func(int, int) int 10 functions[0] = add 11 functions[1] = mul 12 13 fmt.Printf("functions[0](2, 3) = %d\n", functions[0](2, 3)) 14 fmt.Printf("functions[1](2, 3) = %d\n", functions[1](2, 3)) 15}

完全に前置にする場合、長い型が出てくると変数名がかなり後ろになってしまいますし、パース時も型がどの部分なのか判定しづらいので、後置にするという選択がされたのだと考えています。

投稿2019/05/13 00:16

編集2019/05/14 07:27
IgaguriMK

総合スコア148

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Otama_Clever

2019/05/14 06:10

こんにちは。 自分には、こちらの回答が理路明晰ゆえ、気に入りました。 ありがとうございました。参考になりました。 ★誤植(誤記)?:もし、小生の勘違いなら、お許し戴きたいですが、  最終段落↓の★部分は、正しくは「後置」なのかしら? 『完全に前置にする場合、長い型が出てくると変数名がかなり後ろになってしまいますし、パース時も型がどの部分なのか判定しづらいので、★前置にするという選択がされたのだと考えています。』
Otama_Clever

2019/05/14 08:20

ご修正、ありがとうございました。
sin_250

2019/05/19 07:10

関数ポインタを勉強しなおしてみましたが、確かにおっしゃるとおりですね。 すっきりした考え方が得られました。ありがとうございました。
guest

0

もう言語の比較対象に挙げられることすらなくなってしまったけれど
VBは
Dim A as Integer
と、後でしたね。

投稿2019/05/14 13:16

yominet

総合スコア187

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

(以下は全部根拠のない私見です)

Cコンパイラは、今では珍しい事に1パスのコンパイラであり
前から後ろに読み取っていき、基本的に戻りません。
多分、初期のコンピュータの記憶デバイスがテープだった事やメモリが貧弱だった事と関係があったと思っています。

そのため、(配列と関数ポインタを除き)型を前置することが自然でした。

言ってしまえば前置だったのはコンピュータ側の都合です。


型推論を行うようになった理由を考えると
C++においては

c++

1Hoge* f = new Hoge(); 2std::unorderd_map<std::string, std::vector<std::vector<unsigned long long>>> vec = f->list;

のように

  • 1つの変数に対し同じ型名を2度書く場面がたまにあること
  • とてもとても長い型名がSTLを使うと日常的になったこと

が理由だったと推測します。


そして、型推論を得た結果

c++

1auto f = new Hoge(); 2auto vec = f->list;

今度は人間が型が分からなくなる事態が発生しました。

それはそれで困ります。
しかし、長い型を読むのは辛いですしどこが変数名なのかが分からなくては困ります。

そういった事を考えた結果、最近の言語では後置にすることで変数名をわかりやすくしているのかと思います。

投稿2019/05/13 01:18

編集2019/05/14 00:34
asm

総合スコア15149

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuba

2019/05/15 07:16

1パスコンパイラの都合に合っているのはむしろ後置かと存じます。 Pascalのコンパイルが速かったのもそのためと。 (Cの場合、型名を読み取ってもその時点では変数宣言が始まったのか関数宣言が始まったのか確定しておらず、確定するところまで読み進んでバックトラックしなくてはいけません。型後置のPascalなら未定義の識別子を読んだ時点で変数宣言と確定します)
guest

0

前置は型宣言
後置は型注釈で概念が異なります

質問者様が挙げられている関数のシグネチャの例では前置だろうが後置だろうがどっちでもよくで
文法の違いに過ぎないと思ってしまいますが

型注釈の場合は、(変数宣言だけではなく)任意のに対して注釈をつけられます

Scala

11: Long 25 * 6: Long

型注釈というのは型推論が前提になっていて
型宣言がなくてもコードを書ける、だが推論に必要な付加情報を任意の場所に埋め込めるようにしよう
という設計思想だと思います

その場合後置のほうが文法的に都合がよかったのではないでしょうか
変数に対する注釈だろうがリテラルに対する注釈だろうが書き方が一緒で一貫性があるのもいいですね

型宣言型の言語だと一応キャストの文法があるけど括弧の数が増えちゃうから
型推論型の言語では採用されなかったのではないでしょうか

投稿2019/05/16 15:05

Oronine

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/19 07:04

ご回答有り難うございます。実際に型注釈を要する言語を触ってみてイメージが分かりました。 注釈を入れるとエラーメッセージがわかりやすくなったりしますね。 いろいろ勉強になりました。
guest

0

関数でも変数でも、
評価後の結果としてどのような値が取れるか?という事を考えてみると直感的に後置なると思いました。
関数型言語での表記(ramdajsのドキュメントにも見られる)とも一致しています。
https://ramdajs.com/docs/#append

a → [a] → [a]

投稿2019/05/14 13:59

topiinopii

総合スコア47

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

理由は統一のためです。

「前置」だという言語でも、関数引数のカッコ(=関数型であることを意味する修飾)は、関数名の識別子に対して後置にするものが多いですが、前置と後置がごっちゃになっています。
変数の型修飾も、関数に対するものと同じ後置にすることで初めて統一がとれ、統一性を重視する言語設計者を満足させます。

もちろん、関数としての型修飾も含めて、すべて前置に統一することも可能ではあるでしょうし、実際にそんな言語も存在するのかもしれません。
こんな感じでしょうか。

int (int arg)func {...
}

でも、恐らく人気はでないのではないでしょうか。

なお、後置の型修飾は関数以外に配列の[]などでも同じ議論ができます。Cや初期のJavaでは前置後置混在になりました。Javaではある時点で前置になりましたが、違和を感じるひともいたのではないでしょうか。

投稿2019/05/15 13:00

編集2019/05/15 20:52
uehaj

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sin_250

2019/05/19 07:07

確かに・・・。関数のカッコなどあまり意識したことなかったです。 そう考えると確かにモダンな文法のほうが洗練されているような気はたしかにします。 ご回答有り難うございました。
guest

0

重複送信したので削除

投稿2019/05/15 12:56

編集2019/05/15 13:10
uehaj

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

UML図では

filed_name: number
method(): number

のようの型を後ろに書きます。これに倣っているのではないでしょうか?

投稿2019/05/12 07:10

katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問