Live data from Hacker News

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

blog.cloudflare.com

191–200 of 305 posts

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

#191

Really not a big fan of batteries included opinionated protocols. Even Cap'n Proto and Protobuf is too much for me. My particular favorite is this. But then I'm biased coz I wrote it haha. https://github.com/Foundation42/libtuple No, but seriously, it has some really nice properties. You can embed JSON like maps, arrays and S-Expressions recursively. It doesn't care. You can stream it incrementally or use it a messag…

That link is dead

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

#192
post #90
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…

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`…

PonyORM does something similar in Python:

    select(c for c in Customer if sum(c.orders.total_price) > 1000)
I love the hackiness of it.

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

#193
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).

[deleted]

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

#194

Earlier quoted context omitted.

> I find the choice of TypeScript to be disappointing. Genuinely curious, is the disappointment because it's limited to the JS/TS ecosystem? My take is that by going all-in on TypeScript, they get a huge advantage: they can skip a separate schema language and use pure TS interfaces as the source of truth for the API. The moment they need to support multiple languages, they need to introduce a new complex layer (like…

You can generate TypeScript schema for Haxe JS output. I'm honestly a bit surprised that TS isn't a supported target! That could change with some investments. Haxe is a great toolkit to develop libraries in because it reduces the overhead for each implementation. It would be nice to see some commercial entity invest in Haxe or Dafny (which can also enable verification of the reference implementation). > The moment th…

> So this just won't be used outside of Node servers then?

Well... I imagine / hope it will be used a lot on Cloudflare Workers, which is not Node-based, it has its own custom runtime.

(I'm the author of Cap'n Web and also the lead developer for Cloudflare Workers.)

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

#195
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`…

PonyORM does something similar in Python: select(c for c in Customer if sum(c.orders.total_price) > 1000) I love the hackiness of it.

PonyORM is my favourite python ORM.

Along with https://pypi.org/project/pony-stubs/, you get decent static typing as well. It's really quite something.

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

#196
post #174

Earlier quoted context omitted.

Agree -- I think that's a powerful generalization you're making. > We're often nowadays working in dynamic languages, so they become essentially the frontend to new DSLs, and instead of defining new syntax, we embed the AST construction into the scripting language. And I'd say that TypeScript is the real game-changer here. You get the flexibility of the JavaScript runtime (e.g., how Cap'n Web cleverly uses `Proxy`s)…

I do find the pattern interesting and powerful. But at the same time, something feels off about it (just conceptually, not trying to knock your money-making endeavor, godspeed). Some of the issues that all of these hit is: - No printf debugging. Sometimes you want things to be eager so you can immediately see what's happening. If you print and what you see is that's not very helpful. But that's what you'll get when y…

I think this kind of tracing-caused complexity only arises when the language doesn't let you easily represent and manipulate code as data, or when the language doesn't have static type information.

Python does let you mess around with the AST, however, there is no static typing, and let's just say that the ML ecosystem will before they adopt static typing. So it's not possible to build these graphs without doing this kind of hacky nonsense.

For another example, torch.compile() works at the python bytecode level. It basically monkey patches the PyEval_EvalFrame function evaluator of Cpython for all torch.compile decorated functions. Inside that, it will check for any operators e.g BINARY_MULTIPLY involving torch tensors, and it records that. Any if conditions in the path get translated to guards in the resulting graph. Later, when said guard fails, it recomputes the subgraph with the complementary condition (and any additional conditions) and stores this as an alternative JIT path, and muxes these in the future depending on the two guards in place now.

Jax works by making the function arguments proxies and recording the operations like you mentioned. However, you cannot use normal `if`, you use lax.cond(), lax.while(), etc,. As a result, it doesn't recompute graph when different branches are encountered, it only computes the graph once.

In a language such as C#, Rust, or a statically typed lisp, you wouldn't need to do any of this monkey business. There's probably already a way in the rust toolchain to interject at the MIR stage and have your own backend convert these to some Tensor IR.

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

#197

What happens if I pass a recursive function to map()? let traverse = (dir) => { name: dir.name, files: api.ls(dir).map(traverse) // api.ls() returns [] for files }; let tree = api.ls("/").map(traverse);

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?

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

#198
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 before it became overwhelmed, what would these errors look like if they do indeed exist?

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

#199
post #90
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…

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`…

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.

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

#200
I really like the idea. Especially the idea where you return different RpcTargets based on the "context", that's really quite nice. Not just for authentication and such, but for representing various things like "completely structurally different output for GET /thingies for admin and users".

The promise-passing lazily evaluated approach is also nice -- any debugging woes are solved by just awaiting and logging before the await -- and it solves composability at the server - client layer. The hackiness of `map()` is unfortunate, but that's just how JS is.

However, I don't see this being too useful without there also being composability at the server - database layer. This is notoriously difficult in most databases. I wonder what the authors / others here think about this.

For an example of what I mean

  const user = rpc.getUser(id)
  const friends = await rpc.getFriends(user)
Sure beats

  GET /user/id
  GET /graph?outbound=id
But, at the end, both cases are running two different SQL queries. Most of the time when we fuse operations in APIs we do it all the way down to the SQL layer (with a join).

  GET /user/id?include=friends
Which does a join and gets the data in a single query.

So while its a nice programming model for sure, I think in practice we'll end up having a `rpc.getUserAndFriends()` anyways.

I'm not that experienced, so I don't know in how many projects composability at just one layer would actually be enough to solve most composability issues. If it's a majority, then great, but if not, then I don't think this is doing much.

One situation where this actually works that comes to mind is SQLite apps, where multiple queries are more or less OK due to lack of network round trip. Or if your DB is colocated with your app in one of the new fancy datacenters where you get DB RAM to app RAM transfer through some crazy fast network interconnect fabric (RDMA) that's quicker than even local disk sometimes.

Post reply on HN