惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
爱范儿
爱范儿
量子位
博客园 - 聂微东
Engineering at Meta
Engineering at Meta
WordPress大学
WordPress大学
GbyAI
GbyAI
MyScale Blog
MyScale Blog
IT之家
IT之家
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Hugging Face - Blog
Hugging Face - Blog
The Register - Security
The Register - Security
Microsoft Security Blog
Microsoft Security Blog
博客园_首页
MongoDB | Blog
MongoDB | Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Y
Y Combinator Blog
雷峰网
雷峰网
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
博客园 - 叶小钗
D
DataBreaches.Net
B
Blog
B
Blog RSS Feed
大猫的无限游戏
大猫的无限游戏
aimingoo的专栏
aimingoo的专栏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
小众软件
小众软件
腾讯CDC
T
Threat Research - Cisco Blogs
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
D
Docker
Cisco Talos Blog
Cisco Talos Blog
T
Tenable Blog
Webroot Blog
Webroot Blog
宝玉的分享
宝玉的分享

hsfzxjy 的博客

解决 VSCode + CMake + MSVC 编译器信息乱码的问题 使用 3090 部署 1.58bit 动态量化版 DeepSeek R1 671b 如何在 VS Code DevContainer 中配置 HTTP 代理 如何在跳板机背后的服务器上使用 VS Code Remote - Containers Cohesive Digests for Ints and Floats Rust 中的隐匿概念 —— Place(位置) 美术馆 一尺之槌,日取其半,1075日而竭 老生常谈:使用 Cloudflare 自选 IP 加速站点访问 辩义 State、Nation 与 Country 将 Base64 编码的数据快速转换为 Uint8Array 折腾 NPU·第1章 —— 搭建 Level Zero 开发环境 折腾 NPU·第0章 —— Intel NPU 概述与 Level-Zero 新增域名 monad.run CSS 中为特定字符设置不同字体 Arbitary Lifetime Transmutation via Rust Unsoundness Dijkstra 算法的延伸 Manacher 回文计数算法 硬卧 Go Fact: Zero-sized Field at the Rear of a Struct Has Non-zero Size Display *big.Rat Losslessly and Smartly in Golang 代码的仪式 Building Electron From Scratch 中式亲属称谓研究之一:构建半群 Some Notes on Kotlin Coroutines Git sparse-checkout and partial clones for Mega-Repos 辩义“封建” Diving from the CUDA Error 804 into a bug of libnvidia-container Modern Cryptography, GPG and Integration with Git(hub) Move the Root Partition of Ubuntu A New Programmer Kicks a Roadblock Git-based Dependencies in Dart and Go Reversy Naming 人类一败涂地 Invalid Golang Pointers Can Bite You Even If You Don't Dereference Side Project(副业) Initialize Process Pool Worker with Individual Value Rust - Python FFI From Scratch [Extending Hexo For My Site] Part 1 [Extending Hexo For My Site] Part 0 Debug a 'torch.tensor(1).cuda()' hanging 不自由的互联网 Retrieve Contents over HTTP without curl or wget [Unravelling mocona] Part 1 - Verbosity or Anti-Pattern [Unravelling mocona] Part 0 - Preface Understanding pickle in Python Rough Notes on Deploying Vaultwarden & NextCloud Bookmarks 语言狂热者与实用主义者 Demystify the randomness in CUDA kernels Performant Bulk Mutations in IndexedDB Auto Rebuild .pyx Files with pyximport Cython and Threads Obtain a Random Available TCP Port with Bash Information Theory: KL Divergence Information Theory: Entropy and Mutual Information 铁板烧 西郊线 Proof of the Gumbel Max Trick Option::as_ref Rc, RefCell and Interior Mutability Visualizing Correlation 三月十日杂感 三月一日杂感 二月十一日杂感 一月二十六日杂感 SS Configuration 一月七日杂感 四月·病 Haskell 笔记:State Monad Haskell 笔记:Monad 引论 Haskell 笔记:Applicative Haskell 笔记:Category Theory and Functor Haskell 笔记:data, type, newtype Haskell 笔记:folds 使用 Aria2 在 Ubuntu 中下载百度云资源 从伪并行的 Python 多线程说起 一个 Reentrant Error 引发的对 Python 信号机制的探索和思考 Linux 文件权限 HSFZMUN 4.0 部署小记 午后雨·科大 最后的雨夜·广州 揭秘·变态的平方根倒数算法 神坑·Python 装饰类无限递归 Python“黑魔法”之 Encoding & Decoding Ubuntu 重新映射键盘布局 为什么我要翻墙 Python“黑魔法”之 Generator Coroutines 数学美 之 判断线段相交的最简方法 除夕杂感 17 行代码实现的简易 Javascript 字符串模板 Python“黑魔法”之 Meta Classes 诗集 生活,需要被“发现” 家书·十八岁成人礼 炫技?还是需求? 【译】响应式图片的现状 【译】“为什么有这么多的编程语言?” Wisecity 商赛总结——也谈前端自动化测试 记一次 DoS 诈骗网站的经历 那一年,我们望向星空
A Flaw of Promoting Complex Trait Bounds in Rust
2022-03-30 · via hsfzxjy 的博客

Days ago, for some reason, I was trying to implement a function that can polymorphize over its return type. The solution is simple, but my brain was jammed at that time, trapped in some complicated typing tricks for hours.

During the struggling, I coincidently ran into something that is temporarily a flaw in the current Rust compiler implementation. In some cases, the compiler is not smart enough to promote known trait bounds, and we have to replicate them again and again. Although the problem is afterwards proved to be a useless “X-Y Problem”, I would still like to share the story.

The Problem

Let’s say we are going to write a function that digests a given &[u8] slice and computes a hash value. The function would adopt either of two different algorithms, and a u64 or u128 integer is returned as the hash result.

Trivially, this can be achieved by splitting into two functions get_hash_u64() and get_hash_u128(). But I prefer to have a single and unified interface, so concretely, I am expecting a function to polymorphize over its return type, with the following signature

fn get_hash<T>(b: &[u8]) -> T
where
{ todo!() }

Two things I should fill in for the above snippet

  1. The where-clause. Some trait bounds might be satisfied for typevar T, and I expect them to be as concise as possible in order for less verbosity in callers.
  2. The body. The function should behave differently regarding different typevar T.

In order to emulate the effect of choosing different hashing algorithm, we expect a different numeric value be returnedwhen different typevar T supplied. Also, since the argument b: &[u8] is irrelavant to our problem, I will omit it in the following text for brevity. So overall, I would like the two assertions to be held

assert_eq!(get_hash::<u64>(), 42u64);
assert_eq!(get_hash::<u128>(), 4242u128);

The Simple Answer

Before stepping far, I will place a simple and straight-forward solution at the front, in case of anybody taking the same wrong path.

Specifically, we can define a trait, say HashVal, as the upper bound of all possbile return types for get_hash.

trait HashVal: Sized {
fn digest() -> Self;
}

For each possible type such as u64 or u128, we place corresponding hashing algorithm in HashVal::digest

impl HashVal for u64 {
fn digest() -> Self { 42u64 }
}

impl HashVal for u128 {
fn digest() -> Self { 4242u128 }
}

fn get_hash<T: HashVal>() -> T {
T::digest()
}

get_hash<T>() is now polymorphized over return type T. User might select a 64-bit hashing algorithm via a calling like get_hash::<u64>().

This solution is neat and, most importantly, the prerequisite T: HashVal is concise and self-explained, which saves a lot of verbosity in callers’ where-clause. However, this didn’t come to my mind at that time. I alternatively choose a more complicated solution.

The Complicated Answer

In this version, I start by a dummy struct Hasher and a trait HashDispatcher<T>.

type Hasher;

trait HashDispatcher<T> {
fn digest() -> T;
}

The struct Hasher implements HashDispatcher<T> for different type T with corresponding algorithm filled in digest() method

impl HashDispatcher<u64> for Hasher {
fn digest() -> u64 { 42u64 };
}

impl HashDispatcher<u128> for Hasher {
fn digest() -> u128 { 4242u128 };
}

fn get_hash<T>() -> T where Hasher: HashDispatcher<T> {
Hasher::digest()
}

Function get_hash<T>() delegates the calling to Hasher::digest(), which requires a verbose trait bound Hasher: HashDispatcher<T>. In order to reduce the boilerplate, I was seeking to write another trait, named also HashVal, such that for all T being a HashVal, the trait bound Hasher: HashDispatcher<T> holds, or formally $$\text{T: HashVal} \Rightarrow \text{Hasher: HashDispatcher&lt;T&gt;}$$. If achieved, the signature of get_hash can be largely deduced into

fn get_hash<T: HashVal>() -> T;

The Incorrect Attempt for HashVal

The first attempt I made was to place the bound in the where-clause of a generic impl

trait HashVal {};
impl<T> HashVal for T where Hasher: HashDispatcher<T> {}

I mistakenly thought this would fulfill my purpose. The statement instead should read as “for every T that satisfies Hasher: HashDispatcher, T is a HashVal”, which delivers a different implication that converses to what I expect. Thank u/schungx for pointing out in the reddit thread. As a counter-example, one is able to impl other types as HashVal, while without ensuring them to satisfy my bound

impl HashVal for String {}

The Correct yet Flawed Attempt

u/SkiFire13 mentioned that the trait bound should be placed at the definition of HashVal to meet my requirement like this

trait HashVal where Hasher: HashDispatcher<Self> {}

I have no memory of seeing a where clause in the trait definition before. The syntax is not introduced by “The Book”, but rather mentioned in the RFC of where clause.

where-clause for trait is not a new concept. In fact, the “supertrait” bound can be regarded as a specialized version of where-style bound

trait Foo: Bar {}  
trait Foo where Self: Bar {}

More generally, the where-clause is used to elaborate the constraints that the typevars (or the special Self) should satisify. If SomeT: Trait holds, type SomeT should meet all the requirements in Trait‘s where-clause.

As for our case, the where-clause grants an upper bound for HashVal – any type T implements HashVal should satisfy Hasher: HashDispatcher<T> beforehand, which is precisely our requirement.

With this declaration, however, we still cannot deduce the trait bound of get_hash to T: HashVal, due to the flaw of current compiler. A long discussion “where clauses are only elaborated for supertraits, and not other things” can be found on Github back in 2015.

In short words, except from some simple constraints like supertraits, the constraints in where-clause will only be respected within the trait definition (to ensure some type-checks in the trait can pass), but not be promoted in other places.

trait HashVal: Sized where Hasher: HashDispatcher<Self> {
fn foo() -> Self {

<Hasher as HashDispatcher<Self>>::digest()
}
}
impl<T: Sized> HashVal for T where Hasher: HashDispatcher<T> {}


fn get_hash<T: HashVal>() -> T {
Hasher::digest()
}

The flaw is quite annoying. We still have to replicate the verbose trait bounds here and there. Hopefully it can be fixed in the future.


Author: hsfzxjy.
Link: .
License: CC BY-NC-ND 4.0.
All rights reserved by the author.
Commercial use of this post in any form is NOT permitted.
Non-commercial use of this post should be attributed with this block of text.