Skip to content

Instantly share code, notes, and snippets.

View sophiajt's full-sized avatar

Sophia June Turner sophiajt

View GitHub Profile
@sophiajt
sophiajt / a case for nushell laziness.md
Last active June 27, 2022 03:01
A case for Nushell laziness

A case for Nushell laziness

Up to this point, Nushell has been built around the idea that commands stream data from one to the next via a pipeline. This pipeline is implemented as an iterator in Rust, allowing it to lazily compute the output as needed. A pipeline can be created, and only the rows needed are pulled through each stage.

This has served Nushell well. It's a simple, yet powerful, abstraction that commands can build on top of.

That said, I think it's time to experiment with a more powerful model. If this proves successful, it could put Nushell in a much better position for both higher performance but also a much more improved user experience.

Pipelines are too simple

let x = {
let mut foo = Foo::new();
foo.append("bar");
foo.append("baz");
x
};
// or, more commonly:
extern crate syn;
use std::env;
use std::fs;
use std::io::Read;
#[derive(Debug)]
struct File {
functions: Vec<Function>,
}

GUI support in Rust could be built on a central crate that has a common set of GUI components (button, menubar, dropdown, etc). It would also have first-party connectors to the GUI that's "native" for a given platform.

Wrapping native GUI by default means that each app will feel natural for the given platform, including not only the look of the widgets, but also tricky elements like text input would work just as they with native inputs. The native platforms already put a ton of work into getting this right, let's just leverage it.

Because of the difference in platforms, what if the GUI crate didn't take (x,y) coordinates, but instead used a more constraint-based layout mechanism. This may help cut down on the fiddling you have to do when getting it to work well between platforms.

Rust has a very "fluent" style, and it's not uncommon to see people use this to simulate optional named arguments. I think we could use this to give the library a bit of a Rust feel.

Simple example:

trait FnRegister<A, RetVal, Args> {
fn register(&mut self, name: &str, f: A);
}
impl<A, RetVal, Arg1> FnRegister<A, RetVal, (Arg1,)> for Bob
where A: 'static + Fn(Arg1)->RetVal
{
fn register(self, name: &str, fun: fn(Arg1)->RetVal) {
println!("Fn(T)->U");
}
use std::any::Any;
#[derive(Debug)]
struct Engine {
x: i32
}
trait FnRegister<RetVal, Args> {
fn register<T: Fn(Args)->RetVal>(&mut self, name: &str, f: T);
}
use std::any::Any;
#[derive(Debug)]
struct Engine {
x: i32
}
trait FnRegister1V {
fn register<T: Fn(U)->V, U, V>(&mut self, name: &str, f: T);
}
use std::any::Any;
#[derive(Debug)]
struct Engine {
x: i32
}
trait FnRegisterTest {
fn register(self, engine: &mut Engine, name: &str);
}

Try 1: Constrain with FnRegister

pub fn register<T: FnRegister>(&mut self, f: T, name: &str) {
    f.register(self, name);
}

Error: the trait rhai::fn_register::FnRegister is not implemented for the type fn(i32) -> i32 {add} [E0277]