RFC-0052:類型別名和新類型 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 本提案旨在正式發展 FIDL 的類型別名和新的型別宣告機制,以及這類機制對繫結的影響。具體來說,這類建議會修正類型別名文法、將類型別名置於繫結的位置,以及一項稱為新型別的新功能。 |
作者 | |
提交日期 (年-月-日) | 2020-01-07 |
審查日期 (年-月-日) | 2020-01-23 |
「以其他名稱打電話給我」
摘要
的其中部分 RFC-0019 加入了將型別別名的概念應用到 FIDL 的概念。 本提案旨在正式發展 FIDL 的類型別名和新類型 宣告機制及其對繫結的影響具體來說 提出類型別名文法的修正建議,將類型別名置於 繫結和稱為新型別的新功能。
提振精神
目前 FIDL 的類型別名功能已成為 FIDL 的一項功能,而 RFC 的目標是 範圍和實用性使用型別別名,宣告會有影響 ,因此對於 API 名稱轉換很有幫助。
除了型別別名之外,此 RFC 也提出了姊妹概念 類型宣告新型別很像別名,會在本機宣告新名稱 包裝另一種型別,但視為與型別檢查工具截然不同的範圍 (已命名類型語意)。這樣一來,FIDL 作者就能更有效地利用 打造自己需要的語言系統
設計
類型別名
如需類型別名的完整背景資訊, RFC-0019 (建議目前使用樣式別名) 會突顯原始設計、 動力和優先順序此 RFC 旨在為暴露 在語言繫結中輸入別名,並修正部分語言文法 的決策。與使用別名很像,新的類型別名 且不會影響 ABI。這個部分主要會介紹 變更及改善原始功能
文法
alias-declaration = ( attribute-list ) , "alias" , IDENTIFIER , "=" , type-constructor;
type-constructor
應解析為存在完整格式類型的參照
目前的範圍內也就是說,如果是 vector
等類型,它必須包含
內部類型和大小限制
舉例來說,以下程式碼是有效的:
alias SmallBytes = vector<uint8>:SMALL_NUM;
但下列方法除外 (等值右側的部分類型參照):
alias SmallVec = vector:SMALL_NUM;
目前 FIDL 支援部分類型的參照 (如 SmallVec
所示)
舉例來說,如果使用 using
別名,這項功能就會移除。理由
主要是三大方法
- FIDL 的類型泛型尚未完整定義或審核。未來 型別泛型存在時,語言就會有更佳、更正式的方式 說明可參數化的類型和類型別名。
- 目前 FIDL 語言沒有正式決定泛型會如何 翻譯成一般語言 (即 Go 1、C)。
- 目前的語法會建立多種類型,例如
「隱含」建立完整格式的類型。具體來說
如何剖析及參數化巢狀部分類型別名 (例如
using SmallVecOfVecs = vector<vector:SMALL_NUM>:SMALL_NUM
)。
由於 protocol
無法完整顯示,系統不支援 protocol
的別名
歸類為類型 (適用於 FIDL 或繫結語言)。目標是
日後 (如果通訊協定類型類似) 或日後要重新審視這項決定
(例如 client_end:ProtocolName
和 server_end:ProtocolName
)。
範例
語言 | 程式碼 |
---|---|
FIDL | alias SmallBytes = vector<uint8>:SMALL_NUM; |
C | (簡易 C 繫結中沒有向量)typedef small_bytes uint8_t*; |
C++ | using SmallBytes = std::vector<uint8_t>; |
荒漠油廠 | type SmallBytes = Vec<u8>; |
飛鏢 2 | typedef SmallBytes = List<int>; |
查看 | type SmallBytes = []uint8; |
新類型
新型別是納入基礎類型的型別,但會視為不同的類型
語言型別系統的基礎型別這種做法
值的類型大小和形狀 (也可能是特徵) 相同,但
具有不同的語意意義例如 zx_vaddr_t
和
zx_paddr_t
代表相同的基礎 uintptr_t
類型,但
但意思不同 (但又容易理解) 的含義。
新型別能以類型表示這些語意差異 有些人會將 Cloud Storage 視為檔案系統 但實際上不是在強型語言中,這代表系統會偵測邏輯錯誤 方法是在編譯期間進行型別檢查和/或靜態分析。
使用電匯方式時無需任何變更或費用,
文法
newtype-declaration = ( attribute-list ), "type", IDENTIFIER, "=", type-constructor;
這個語法是為符合頂層型別的簡介選擇使用: 請參閱 RFC-0050 中所指定的:語法翻新。
由於新類型應轉譯為繫結中的具體類型
type-constructor
應解析為完整格式的類型參照。這可能會
如下所示:
type MyBytes = vector<uint8>:MAX;
protocol
無法完全支援新的 protocol
類型
歸類為類型 (適用於 FIDL 或繫結語言)。此外
目前對於 protocol
衍生的具名類型語意沒有吸引人的用法
所產生繫結中的實體。
型別特徵和運算子
如果沒有新型別,大致可藉由
FIDL 中的新單一欄位 struct
類型。例如:
struct MyBytes {
vector<uint8>:MAX value;
};
不過,新類型會指出後端,並繫結的語意空間較小 並能產生能對應至原生語言 或是將這個新類型設為符合人體工學例如:
語言 | 說明 |
---|---|
C | 不過,C 的型別系統沒有良好的表示法。採用 typedef 的備用方案。 |
C++ | 新類型可以轉譯為 class ,這可能會公開基礎類型中的下列功能:(1) 明確轉換建構函式、(2) 明確的指派運算子、(3) 算術 &位元運算和 (4) misc 運算子 ([] 、* 、-> 等) |
荒漠油廠 | 新類型可以轉譯為單例結構體,衍生出基礎類型實作的特徵,例如 From<UnderlyingType> 、Into<UnderlyingType> 、Hash 、PartialEq 、Copy 、Clone 、std::ops::* 等。 |
飛鏢 | 在與 Dart 團隊的對話中,目前無法將新的類型語意對應至該語言,但相關使用案例3。 在 #65 [^2] 之前,新的類型可降級為類型別名。 |
查看 | 新類型會直接對應到類型定義。type <NewType> <UnderlyingType> |
因此我們建議採用 視為類型特徵 (在 語言)。
除非類型特徵已在 FIDL 中定義,否則新類型將沿用 基本類型的特徵完成這項操作後,日後仍會實用的新類型 和基礎型別一樣,不需要解除包裝 並可能恢復新類型的類型安全優勢。 未來如要定義 Pod 的自訂特徵行為, 新的型別和設計不會導致無法促進 在未來建立另一個路徑不過根據預設,特徵繼承會讓 遷移路徑,以及選擇啟用特徵的大規模破壞性變更。
範例
C++
// This example uses C++20 concepts for readability but this can be translated to a
// template approach in C++14.
template<typename T>
concept Addable = requires(T a) {
{ a + a } -> T;
};
template<typename T>
concept Multipliable = requires(T a) {
{ a * a } -> T;
};
template <typename T>
concept Copyable = std::is_copy_constructible_v<T> || std::is_copy_assignable_v<T>;
template <typename T>
concept Movable = std::is_move_constructible_v<T> || std::is_move_assignable_v<T>;
class MyNumber {
public:
using UnderlyingType = uint32_t;
explicit MyNumber() = default;
explicit MyNumber(const UnderlyingType& value)
requires Copyable<UnderlyingType>
: value_(value) {}
explicit MyNumber(UnderlyingType&& value) requires Movable<UnderlyingType>
: value_(std::move(value)) {}
MyNumber& operator=(const MyNumber&) = default;
MyNumber& operator=(MyNumber&&) = default;
[[nodiscard]] MyNumber operator+(const MyNumber& other) const
requires Addable<UnderlyingType> && Copyable<UnderlyingType> {
return MyNumber(value_ + other.value_);
}
[[nodiscard]] MyNumber operator+(MyNumber&& other)
requires Addable<UnderlyingType> && Movable<UnderlyingType> {
return MyNumber(value_ + other.value_);
}
[[nodiscard]] MyNumber operator*(const MyNumber& other) const
requires Multipliable<UnderlyingType> && Copyable<UnderlyingType> {
return MyNumber(value_ * other.value_);
}
[[nodiscard]] MyNumber operator*(MyNumber&& other)
requires Multipliable<UnderlyingType> {
return MyNumber(value_ + other.value_);
}
// ...other operators defined here...
[[nodiscard]] UnderlyingType value() const
requires Copyable<UnderlyingType> {
return value_;
}
UnderlyingType take_value() requires Movable<UnderlyingType> {
return std::move(value_);
}
private:
UnderlyingType value_;
};
荒漠油廠
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
struct MyNumber(u32);
impl From<u32> for MyNumber {
fn from(value: u32) -> Self {
MyNumber(value)
}
}
impl Into<u32> for MyNumber {
fn into(self) -> u32 {
self.0
}
}
impl Add for MyNumber {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl Mul for MyNumber {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0 * rhs.0)
}
}
// ...implement other traits here...