
Faut-il arrêter d’initier de nouveaux projets en C++ et passer à Rust ?
Faut-il arrêter d’initier de nouveaux projets en C++ et passer à Rust ? Oui, d’après Mark Russinovich de Microsoft qui recommande le langage Rust plutôt que le C ou C++. Les raisons : la parité en termes de vitesse d’exécution en comparaison avec le C ; la sécurisation et la fiabilité du Rust en comparaison avec C ou C++. La comparaison entre Rust et C++ vient de prendre un coup de neuf avec une sortie de la startup RisingWave. Elle s’est lancée dans un projet de mise sur pied d’un SGBD Cloud natif avec le langage C++. 7 mois après son lancement le projet en C++ a été abandonné pour une réécriture en Rust. L’éditeur donne ses raisons.
Les comparatifs des langages Rust et C++ ont un dénominateur commun : la mise en avant de la supériorité de Rust à C++ en matière de sécurisation de la mémoire. Celui de la startup RisingWave ne s’en écarte pas et souligne que :
« Rust garantit la sécurisation de la mémoire et des threads au moment de la compilation en introduisant des règles de propriété. Il va au-delà du RAII, un mécanisme de gestion de la mémoire couramment utilisé en C++. Il présente deux avantages. Le premier est évident : une fois que le compilateur Rust a validé notre programme, nous n'aurons pas de défauts de segmentation ou de conditions de concurrence lors de l'exécution, ce qui nécessiterait des dizaines d'heures de débogage, en particulier dans une base de code hautement concurrente et principalement asynchrone. La seconde est plus subtile : le compilateur Rust restreint simplement les types de fautes, ce qui réduit les fragments de code étroitement imbriqués qui peuvent causer un tel comportement bogué. La réplication des bogues est considérablement améliorée avec l'aide de l'exécution déterministe. »
Néanmoins, Bjarne Stroustrup s’inscrit en faux avec le fait que les comparatifs entre Rust et C++ limitent la notion de sécurisation des logiciels à celle de sécurisation de la mémoire : « Il n'y a pas qu'une seule définition de la notion de "sécurité" et nous pouvons réaliser une variété de types de sécurité par une combinaison de styles de programmation, de bibliothèques de support et grâce à la mise à profit de l'analyse statique. » Bjarne Stroustrup suggère ainsi que ce qu’il est possible d’obtenir du C++ en matière de sécurisation des logiciels dépend entre autres du développeur et notamment de la connaissance des outils que lui offre le langage, de sa maîtrise du compilateur, etc.
Des ingénieurs de Google au fait de ce que le C++ leur offre comme possibilités se sont donc lancés dans la mise sur pied dans ce langage d’un borrow-checker. C’est une fonctionnalité du compilateur Rust qui garantit la sécurisation de la mémoire grâce à une gestion des allocations en mémoire des pointeurs.
L’équipe de Google dont la publication est parue au troisième trimestre de l’année précédente est parvenue à la conclusion que le système de types du C++ ne se prête pas à un tel exercice. Et donc que la sécurisation de la mémoire en C++ est réalisable avec des vérifications lors de l’exécution du programme. En d’autres termes, c’est avec du code C++ lent qu’il est possible d’atteindre un niveau de sécurisation équivalent à celui du Rust.
[CODE=Rust]
pub enum Components {
#[clap(name = "minio")]
Minio,
Hdfs,
PrometheusAndGrafana,
Etcd,
Kafka,
@@ -77,6 +78,7 @@ impl Components {
pub fn title(&self) -> String {
match self {
Self::Minio => "[Component] Hummock: MinIO + MinIO-CLI",
Self::Hdfs => "[Component] Hummock: Hdfs Backend",
Self:

Self::Etcd => "[Component] Etcd",
Self::Kafka => "[Component] Kafka",
@@ -97,6 +99,10 @@ impl Components {
match self {
Self::Minio => {
"
Required by Hummock state store."
}
Self::Hdfs => {
"
Required by Hummock state store."
}
Self:

@@ -169,6 +175,7 @@ Required if you want to create CDC source from external Databases.
pub fn from_env(env: impl AsRef<str>) -> Option<Self> {
match env.as_ref() {
"ENABLE_MINIO" => Some(Self::Minio),
"ENABLE_HDFS" => Some(Self::Hdfs),
"ENABLE_PROMETHEUS_GRAFANA" => Some(Self:

"ENABLE_ETCD" => Some(Self::Etcd),
"ENABLE_KAFKA" => Some(Self::Kafka),
@@ -188,6 +195,7 @@ Required if you want to create CDC source from external Databases.
pub fn env(&self) -> String {
match self {
Self::Minio => "ENABLE_MINIO",
Self::Hdfs => "ENABLE_HDFS",
Self:

Self::Etcd => "ENABLE_ETCD",
Self::Kafka => "ENABLE_KAFKA",
Self:

Self::Redis => "ENABLE_REDIS",
Self::RustComponents => "ENABLE_BUILD_RUST",
Self:

Self::Tracing => "ENABLE_COMPUTE_TRACING",
Self::Release => "ENABLE_RELEASE_PROFILE",
Self::AllInOne => "ENABLE_ALL_IN_ONE",
Self::Sanitizer => "ENABLE_SANITIZER",
Self::ConnectorNode => "ENABLE_RW_CONNECTOR",
}
.into()
}
pub fn default_enabled() -> &'static [Self] {
&[Self::RustComponents]
}
}
fn configure(chosen: &[Components]) -> Result<Option<Vec<Components>>> {
println!("=== Configure RiseDev ===");
let all_components = all::<Components>().collect_vec();
const ITEMS_PER_PAGE: usize = 6;
let items = all_components
.iter()
.map(|c| {
let title = c.title();
let desc = style(
("\n".to_string() + c.description().trim())
.split('\n')
.join("\n "),
)
.dim();
(format!("{title}{desc}",), chosen.contains(c))
})
.collect_vec();
let Some(chosen_indices) = MultiSelect::new()
.with_prompt(
format!(
"RiseDev includes several components. You can select the ones you need, so as to reduce build time\n\n{}: navigate\n{}: confirm and save {}: quit without saving\n\nPick items with {}",
style("↑ / ↓ / ← / → ").reverse(),
style("Enter").reverse(),
style("Esc / q").reverse(),
style("Space").reverse(),
)
)
.items_checked(&items)
.max_length(ITEMS_PER_PAGE)
.interact_opt()? else {
return Ok(None);
};
let chosen = chosen_indices
.into_iter()
.map(|i| all_components[i])
.collect_vec();
Ok(Some(chosen))
}
fn main() -> Result<()> {
let opts = RiseDevConfigOpts::parse();
let file_path = opts.file;
let chosen = {
if let Ok(file) = OpenOptions::new().read(true).open(&file_path) {
let reader = BufReader::new(file);
let mut enabled = vec![];
for line in reader.lines() {
let line = line?;
if line.trim().is_empty() || line.trim().starts_with('#') {
continue;
}
let Some((component, val)) = line.split_once('=') else {
println!("invalid config line {}, discarded", line);
continue;
};
if component == "RISEDEV_CONFIGURED" {
continue;
}
match Components::from_env(component) {
Some(component) => {
if val == "true" {
enabled.push(component);
}
}
None => {
println!("unknown configure {}, discarded", component);
continue;
}
}
}
enabled
} else {
println!(
"RiseDev component config not found, generating {}",
file_path
);
Components::default_enabled().to_vec()
}
};
let chosen = match &opts.command {
Some(Commands:

println!("Using default config");
Components::default_enabled().to_vec()
}
Some(Commands::Enable { component }) => {
let mut chosen = chosen;
chosen.push(*component);
chosen
}
Some(Commands:

chosen.into_iter().filter(|x| x != component).collect()
}
None => match configure(&chosen)? {
Some(chosen) => chosen,
None => {
println!("Quit without saving");
println!("=========================");
return Ok(());
}
},
};
println!("===[/]...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.