Hacker Newsnew | past | comments | ask | show | jobs | submit | nesarkvechnep's commentslogin

There's FreeBSD's Capsicum. It's a full-blown sandboxing mode and capability framework. Unfortunately, Linux didn't adopt it and chose chaos.

Early Hip Hop DJs used this exact property to go straight to the drum break and not waste time waiting for it.

I’ve been doing Elixir for 9 years, 5 professionally. Nobody cares about ad-hoc polymorphism. The community doesn’t use protocols except “for data”. Whatever that means. Global singleton processes everywhere. I’m really discouraged by the practices I observe but it’s the most enjoyable language for me still.


>I’ve been doing Elixir for 9 years, 5 professionally. Nobody cares about ad-hoc polymorphism.

That’s true for Elixir as practiced, but it’s the wrong conclusion for Gleam.

Elixir doesn’t care about ad-hoc polymorphism because in Elixir it’s a runtime convention, not a compile-time guarantee. Protocols don’t give you universal quantification, exhaustiveness, coherence, or refactoring safety. Missing cases become production crashes, not compiler errors. So teams sensibly avoid building architecture on top of them.

In a statically typed language, ad-hoc polymorphism is a different beast entirely. It’s one of the primary ways you encode abstraction safely. The compiler enforces that implementations exist, pushes back on missing cases, and lets you refactor without widening everything into explicit pattern matches.

That’s exactly why people who like static types do care about it.

Pointing to Elixir community norms and concluding “nobody cares” is mixing up ecosystem habits with language design. Elixir doesn’t reward those abstractions, so people don’t use them. Gleam is explicitly targeting people who want the compiler to carry more of the burden.

If Gleam is “Elixir with types,” fine, lack of ad-hoc polymorphism is consistent. If it’s “a serious statically typed language on the BEAM,” then the absence is a real limitation, not bikeshedding.

Static types aren’t about catching typos. They’re about moving failure from runtime to compile time. Ad-hoc polymorphism is one of the main tools for doing that without collapsing everything into concrete types.

That’s why the criticism exists, regardless of how Elixir codebases look today.


Well, for the specific example I gave (JSON serialization), you certainly do care whether Jason.Encoder is implemented for a struct.


Yes, I just ranted, sorry. I share your view about Gleam.


IMHO this is an education problem.


Problem which plagues 90% of the people? How to overcome it?


It's an education problem on two fronts. People inside the ecosystem need to know about it. And also people too deep in the elixir ecosystem who don't know how ad-hoc polymorphism is supposed to be used in a statically typed language.

Both overcome it by admitting they don't know and need to learn.


Argh, a few screenshots would’ve been nice. There’s none to be found in vui.el’s repository.


Agreed, especially since org-mode (which I bet this blog post was written in) supports (inline) images in its exporters.


It’s just a feeling, man.


For 10+ years in the industry I can safely say that almost nobody knows or cares about HTTP caching. It’s sad.


I thought it is something like Liquid Haskell...



If we embraced REST, as Roy Fielding envisioned it, we wouldn't have this, and all similar, conversations. REST doesn't expose identifier, it only exposes relationships. Identifiers are an implementation details.


I'm thinking of using C++ for a personal project specifically for the lambdas and RAII.

I have a case where I need to create a static templated lambda to be passed to C as a pointer. Such thing is impossible in Rust, which I considered at first.


Yeah, Rust closures that capture data are fat pointers { fn*, data* }, so you need an awkward dance to make them thin pointers for C.

    let mut state = 1;
    let mut fat_closure = || state += 1;
    let (fnptr, userdata) = make_trampoline(&mut &mut fat_closure);

    unsafe {
        fnptr(userdata);
    }

    assert_eq!(state, 2);

    use std::ffi::c_void;
    fn make_trampoline<C: FnMut()>(closure: &mut &mut C) -> (unsafe fn(*mut c_void), *mut c_void) {
        let fnptr = |userdata: *mut c_void| {
            let closure: *mut &mut C = userdata.cast();
            (unsafe { &mut *closure })()
        };
        (fnptr, closure as *mut _ as *mut c_void)
    }
    
It requires a userdata arg for the C function, since there's no allocation or executable-stack magic to give a unique function pointer to each data instance. OTOH it's zero-cost. The generic make_trampoline inlines code of the closure, so there's no extra indirection.


> Rust closures that capture data are fat pointers { fn, data }

This isn’t fully accurate. In your example, `&mut C` actually has the same layout as usize. It’s not a fat pointer. `C` is a concrete type and essentially just an anonymous struct with FnMut implemented for it.

You’re probably thinking of `&mut dyn FnMut` which is a fat pointer that pairs a pointer to the data with a pointer to a VTable.

So in your specific example, the double indirection is unnecessary.

The following passes miri: https://play.rust-lang.org/?version=nightly&mode=debug&editi...

(did this on mobile, so please excuse any messiness).


This is a problem for all capturing closures though, not just Rust's. A pure fn-ptr arg can't have state, and if there's no user data arg then there's no way to make a trampoline. If C++ was calling a C API with the same constraint it would have the same problem.

Well, capturing closures that are implemented like C++ lambdas or Rust closures anyway. The executable stack crimes do make a thin fn-ptr with state.


If Rust has a stable ABI on where the data* is in the function arguments (presumably first?), you don't need to do anything if it matches the C code's expected function signature including the user context arg.

Unfortunately a lot of existing C APIs won't have the user arg in the place you need it, it's a mix of first, last, and sometimes even middle.


I know about this technique but it uses too much unsafe for my taste. Not that it's bad or anything, just a personal preference.


It can be done in 100% safe code as far as Rust is concerned (if you use `dyn Fn` type instead of c_void).

The only unsafe here is to demonstrate it works with C/C++ FFI (where void* userdata is actually not type safe)


Yes but my problem wasn’t with the user data pointer but the fact that I needed a STATIC generic lambda. Static because the C library then forks and continues to call the lambda in the new process but I also type based conversions in it.


In Rust, could you instead use a templated struct wrapping a function pointer along with #[repr(C)]?


I’m yet to see a spreadsheet workflow successfully replaced by something else.


Programming in a spreadsheet is an anti-pattern. Does anyone review your workflow? Write tests for it? Use a real programming language; a notebook at least.


Streamlit apps or similar are doing a great job at this where I'm at.

As simple to build and deploy as Excel, but with the right data types, the right UI, the right access and version control, the right programming language that LLMs understand, the right SW ecosystem and packages, etc.


Are they actually as simply to deploy as Excel? My guess would be that most streamlit apps never make it further than the computer they're written on.


If you have the right tooling (e.g. Streamlit.io) then yes, literally.

To 'deploy' an Excel file I go to Office365 and create my excel file and hit share

To 'deploy' a Streamlit file I go to Streamlit and write my single file python code (can be a one liner) and hit share


maybe the strategy in those cases is to augment the core spreadsheet with tools that can unit test it and broadcast changes etc


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: