Live data from Hacker News

Cap'n Web: a new RPC system for browsers and web servers

blog.cloudflare.com

241–250 of 305 posts

Re: Cap'n Web: a new RPC system for browsers and web servers

#241
post #57

The section on how they solved arrays is fascinating and terrifying at the same time https://blog.cloudflare.com/capnweb-javascript-rpc-library/#... . > .map() is special. It does not send JavaScript code to the server, but it does send something like "code", restricted to a domain-specific, non-Turing-complete language. The "code" is a list of instructions that the server should carry out for each member of the arra…

This record and replay trick is very similar to what I recently used to implement the query DSL for Tanstack DB ( https://tanstack.com/db/latest/docs/guides/live-queries ). We pass a RefProxy object into the where/select/join callbacks and use it to trace all the props and expressions that are performed. As others have noted you can't use js operators to perform actions, so we built a set of small functions that we c…

As I understand it it's basically how Pytorch works. A clever trick but also super confusing because while it seems like normal code, as soon as you try and do something that you could totally do in normal code it doesn't work:

  let friendsWithPhotos = friendsPromise.map(friend => {
    return {friend, photo: friend.has_photo ? api.getUserPhoto(friend.id) : default_photo};
  }
Looks totally reasonable, but it's not going to work properly. You might not even realise until it's deployed.

Re: Cap'n Web: a new RPC system for browsers and web servers

#242
Brilliantly engineered but this is solving all the wrong problems. The author implicates that this is supposed to be a better GraphQL/REST, but the industry is already moving towards a better solution for that[1]: data sync like ElectricSQL/Turso/litefs/RxDb. If you want to collapse the API boundary between server and client so that it "feels like" the server and client are the same, then sync the relevant data so it actually IS the same. Otherwise DON'T pretend it is the same because you will have badly leaking abstractions. This looks like it breaks all of the assumptions that programmers have about locally running code. Now every time I do a function call() I have to think about how to handle network failures and latency?

What this could've been is a better way to consume external APIs to avoid the SDK boilerplate generation dance. But the primary problems here are access control, potentially malicious clients, and multi-language support, none of which are solved by this system.

In short, if you're working over a network boundary, better keep that explicit. If you want to pretend the network boundary doesn't exist, then let a data sync engine handle the network parts and only write local code. But why would you write code that pretends to be local but is actually over a network boundary? I can't think of a single case where I would want to do that, I'd rather explicitly deal with the network issues so I can clearly see where the boundary is.

[1] https://bytemash.net/posts/i-went-down-the-linear-rabbit-hol...

Re: Cap'n Web: a new RPC system for browsers and web servers

#243
post #228
post #199

Earlier quoted context omitted.

C#, Swift, Dart, Rust... Python. Many languages take lambda/predicate/closure as filter/where. It generally unrolls as a `for loop` underneath, or in this case LINQ/SQL. C# was innovative for doing it first in the scope of SQL. I remember the arrival of LINQ... Good times.

How many of those languages can take an expression instead of a lambda? Func is lambda that can only be invoked. Expression > is an AST of a lambda that can be transformed by your code/library.

R let's you do that, and it gets used by the tidy verse libraries to do things like change the scope variables in the functions are looked up in.

Re: Cap'n Web: a new RPC system for browsers and web servers

#244
post #90

Earlier quoted context omitted.

In C#, there's expression trees which handle things like this and it's how Entity Framework is able to convert the lambdas it's given into SQL. This means that you can pass around code that can be inspected or transformed instead of being executed. Take this EntityFramework snippet: db.People.Where(p => p.Name == "Joe") `Where` takes an `Expression > predicate`. It isn't taking the `Func` itself, but an `Expression`…

Is there anything C# _doesn’t_ have? :-) It feels like C# has an answer to every problem I’ve ever had with other languages - dynamic loading, ADTs with pattern matching, functional programming, whatever this expression tree is, reflection, etc etc. Yet somehow it’s still a niche language that isn't widely used (outside of particular ecosystems).

As someone who dislikes clutter, in my experience it's just easier to read and write with these languages: Perl, PHP, Ruby, Python, Javascript, Smalltalk.

If you dare leave the safety of a compiler you'll find that Sublime Merge can still save you when rewriting a whole part of an app. That and manual testing (because automatic testing is also clutter).

If you think it's more professional to have a compiler I'd like to agree but then why did I run into a PHP job when looking for a Typescript one? Not an uncommon unfolding of events.

Re: Cap'n Web: a new RPC system for browsers and web servers

#245
post #97
post #95

Earlier quoted context omitted.

thank you. So indeed it's, as corrrectly described, schemaless i.e. schema agnostic, which falls into "schema responsibility being passed to user/dev" (I should have picked up what it means when writing that). So it's basically Stubby/gRPC. From strictly a RPC perspective this makes sense (i guess to the same degree gRPC would be agnostic to protobuf serialization scheme, which IIRC is the case (also thinking Stubby…

> So it's basically Stubby/gRPC. Stubby / gRPC do not support object capabilities, though. I know that's not what you meant but I have to call it out because this is a huuuuuuuge difference between Cap'n Proto/Web vs. Stubby/gRPC. > a ton of responsibility on the user/dev —i.e. the same amount that prompted protobuf to exist, afterall. In practice, people should use TypeScript to specify their Cap'n Web APIs. For peo…

Not the person you were discussing with, but I have to add that to me the main benefit of using Stubby et al. was exactly the schema that was so nicely searchable.

I currently work in a place where the server-server API clients are generated based on TypeScript API method return types, and it's.. not great. The reality of this situation quickly devolves the types using "extends" from a lot of internal types that are often difficult to reason about.

I know that it's possible for the ProtoBuf types to also push their tendrils quite deep into business code, but my personal experience has been a lot less frustrating with that than the TypeScript return type being generated into an API client.

Re: Cap'n Web: a new RPC system for browsers and web servers

#246

This looks awesome, I had two questions: Is there a structured concurrency library being used to manage the chained promise calls and lazy evaluation (IE when the final promise result is actually awaited) of the chained functions? If an await call is never added, would function calls continue to build up taking up more and more memory - I imagine the system would return an error and clear out the stack of calls befor…

> Is there a structured concurrency library being used to manage the chained promise calls

Cap'n Web has no dependencies at all. All the chaining is implemented internally. Arguably, this is the main thing the library does; without promise chaining you could cut out more than half the code.

> If an await call is never added, would function calls continue to build up taking up more and more memory

Yes. I recommend implementing rate limits and/or per-session limits on expensive operations. This isn't something the library can do automatically since it has no real idea how expensive each thing is. Note you can detect when the client has released things by putting disposers on your return values, so you can keep count of the resources the client is holding.

Re: Cap'n Web: a new RPC system for browsers and web servers

#247
post #197

Earlier quoted context omitted.

I believe this will stack-overflow on the client side. The callback is invoked in recording mode synchronously when you call `.map()`. Nested maps are allowed, but this case ends up being infinitely nested, so eventually you're going to hit a stack overflow while trying to do the recording.

What prevents an attacker from using nested maps to make the server spend exponential amounts of CPU and memory on the response? Is there some kind of limit on the total number of response items?

The application should track resource use and implement limits as needed.

I know that sounds like a cop-out, but this is really true of any protocol, and the RPC protocol itself has no real knowledge of the cost of each operation or how much memory is held, so can't really enforce limits automatically.

Re: Cap'n Web: a new RPC system for browsers and web servers

#248

Earlier quoted context omitted.

I think any other syntax would likely be cumbersome. What we actually want to express here is function-shaped: you have a parameter, and then you want to substitute it into one or more RPC calls, and then compute a result. If you're going to represent that with a bunch of data structures, you end up with a DSL-in-JSON type of thing and it's going to be unwieldy.

I suspect there is prior work to draw from that could make this feasible for you... Have a look at how something like MongoDB handles conditional logic for example.

Yeah that's what I mean by DSL-in-JSON. I think it's pretty clunky. It's also (at least in Mongo's formulation, at least when I last used it ~10 years ago) very vulnerable to query injection.

Re: Cap'n Web: a new RPC system for browsers and web servers

#249
post #90

Earlier quoted context omitted.

In C#, there's expression trees which handle things like this and it's how Entity Framework is able to convert the lambdas it's given into SQL. This means that you can pass around code that can be inspected or transformed instead of being executed. Take this EntityFramework snippet: db.People.Where(p => p.Name == "Joe") `Where` takes an `Expression > predicate`. It isn't taking the `Func` itself, but an `Expression`…

Is there anything C# _doesn’t_ have? :-) It feels like C# has an answer to every problem I’ve ever had with other languages - dynamic loading, ADTs with pattern matching, functional programming, whatever this expression tree is, reflection, etc etc. Yet somehow it’s still a niche language that isn't widely used (outside of particular ecosystems).

Good abstractions around units (Apologies if there is a specific terminology that I should use.)

Specifically, I'd like to be able to have "inches" as a generic type, where it could be an int, long, float, double. Then I'd also like to have "length" as a generic type where it could be inches as a double, millimeters as a long, ect, ect.

I know they added generic numbers to the language in C# 7, so maybe there is a way to do it?

Re: Cap'n Web: a new RPC system for browsers and web servers

#250

Earlier quoted context omitted.

The round trip happens when you `await` the result. You can tell that promise pipelining isn't adding any round trips because you set it all up in a series of statements without any `await`s. At the end you do one `await`. That's your round trip.

You say "round trip", but you mean "return trip", right? Because if I understand correctly, you don't queue the requests and then perform a single request/response cycle (a "round trip"), you send a bunch of requests as they happen with no response expected, then when an await happens, you send a message saying "okay, that's all, please send me the result" and get a response.

In HTTP batch mode, they're all sent as a batch.

In WebSocket mode, yes, you are sending messages with each call. But you're not waiting for anything before sending the next message. It's not a round trip until you await something. As far as round trips are concerned, there is really no difference between sending multiple messages vs. a single batch message, if you are ultimately only waiting for one reply at the end.

Post reply on HN