"Capabilities" in cml feels like a double declaration?

12 views
Skip to first unread message

Shai Barack

unread,
Jul 12, 2021, 11:00:25 AM7/12/21
to component-framework-dev
Hi folks,
If I offer or expose or expose a capability from "self", why do I also need to declare it under capabilities in the same cml file? Feels like stating the same thing twice.
Sorry if this has already been discussed and I'm just out of touch. 

Hunter Freyer

unread,
Jul 12, 2021, 11:20:52 AM7/12/21
to Shai Barack, component-framework-dev
I think it has been discussed somewhere... maybe as part of CTP-035? But it's not in the doc itself.

From CapabilityDecl, it seems that the main point is to provide a layer of indirection between "where the component puts the capability in the outgoing directory" and "the name of the capability itself". Like, you can have a capability named "Foo" hosted at "/svc/Bar" in your outgoing directory. I dunno if anyone relies on that, but if they do, I suspect there may be a better way to address their use case.

DirectoryDecl also allows you to put a cap on the rights of a directory, but really you could derive that as the least-upper-bound of all of the "offers" and "exposes" referencing that directory.

Lastly StorageDecl.... I don't really understand StorageDecl. So maybe it's necessary there?

I agree, it seems like a bit of complexity I'd rather remove by being more prescriptive about the mapping between capability names and filesystem paths. But I might be missing something.

Hunter

--
All posts must follow the Fuchsia Code of Conduct https://fuchsia.dev/fuchsia-src/CODE_OF_CONDUCT or may be removed.
---
You received this message because you are subscribed to the Google Groups "component-framework-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to component-framewo...@fuchsia.dev.
To view this discussion on the web visit https://groups.google.com/a/fuchsia.dev/d/msgid/component-framework-dev/CAK0PkCEuvNPmhW8tDX-Q%3DAQD7D2v-btvZHid-_-Ax3C7%2BmJK%2BQ%40mail.gmail.com.

Gabe Schine

unread,
Jul 12, 2021, 12:41:54 PM7/12/21
to Hunter Freyer, Shai Barack, component-framework-dev
+1 to the comments so far.

Shai/Hunter, I'm trying to address some of these things in documentation updates, and preparing for proposing some simpler terminology in CML files. Happy to chat about it if you have the interest.



--
Gabe Schine
Software Engineer / Manager

Rich Kadel

unread,
Jul 12, 2021, 1:00:42 PM7/12/21
to Gabe Schine, Hunter Freyer, Shai Barack, component-framework-dev
There was a long email thread in late Feb or so. It covered things like redundancy, ideas for streamlining CML, and thoughts on how to address common areas of confusion. We wanted to move it out of the email thread into something more structured, so I tried to capture the key ideas in this doc:


Some of the proposed changes are (you could say) a slightly radical departure from the current CML spec.

Eventually the dialog tapered off (lack of a champion, perhaps?).

Rich



Gabe Schine

unread,
Jul 12, 2021, 7:51:21 PM7/12/21
to Rich Kadel, Hunter Freyer, Shai Barack, component-framework-dev, Aaron Wood
Thanks, Rich, for digging that up.

There is definitely an opportunity to improve CML. There's also a risk of this class of work becoming a time-sink. I would like to encourage a gradual convergence to a component configuration that is more intuitive, but I would like to discourage acting on the outcomes of discussions in the short term. We have more to learn by performing more migrations, and it would be a shame not to take advantage of that learning.

My proposal is, for the short term, to improve documentation. For example, I attempt to clarify routing / capability CML concepts in this CL:


Long term, we may want to consider renaming and combining some concepts so that it is easier for a new developer to get up to speed quickly. It took me too long (IMHO), as a new-developer proxy, to grasp the CML concepts. I wrote a longer response, but then decided to delete it because it went on a tangent into proposing future terminology. Ping me if you're curious. :)

Gabe

Gary Bressler

unread,
Jul 12, 2021, 9:13:58 PM7/12/21
to Gabe Schine, Rich Kadel, Hunter Freyer, Shai Barack, component-framework-dev, Aaron Wood
`capabilities` is separate from `expose`/`offer` to reflect the distinction between 'routing' and 'definition'.

A capability should only be defined once, but could be routed multiple times. For example, a `directory` capability has `rights` and `path` settings. If there are multiple routing declarations (`offer` and `expose` for example, but possibly also multiple `offer`s split up, etc.) we don't want the user to redefine the capability multiple times.

Here's the original design that introduced this change: go/ctp-023. We approached this from the philosophy that we should start with an explicit syntax that exposes the underlying conceptual boundaries, even if it's more verbose.

However, I think we could have our cake and eat it too. If a capability is only routed once, which is by far the common case, we could support a combined syntax where the `expose/offer from self` auto-generates the `capability`. The tradeoff, of course, is a more complicated syntax. If this sounds interesting to anyone I encourage you to write a proposal!

Shai Barack

unread,
Jul 12, 2021, 10:25:10 PM7/12/21
to Gary Bressler, Gabe Schine, Rich Kadel, Hunter Freyer, component-framework-dev, Aaron Wood
Thank you for the extra context Gary. 

Hunter Freyer

unread,
Jul 13, 2021, 10:05:03 AM7/13/21
to Gary Bressler, Gabe Schine, Rich Kadel, Shai Barack, component-framework-dev, Aaron Wood
On Mon, Jul 12, 2021 at 9:13 PM Gary Bressler <g...@google.com> wrote:
`capabilities` is separate from `expose`/`offer` to reflect the distinction between 'routing' and 'definition'.

A capability should only be defined once, but could be routed multiple times. For example, a `directory` capability has `rights` and `path` settings. If there are multiple routing declarations (`offer` and `expose` for example, but possibly also multiple `offer`s split up, etc.) we don't want the user to redefine the capability multiple times.

Here's the original design that introduced this change: go/ctp-023. We approached this from the philosophy that we should start with an explicit syntax that exposes the underlying conceptual boundaries, even if it's more verbose.

So, I've been trying for a like an hour now to write an email about whether it's necessary to even have the notion of a component "defining" a capability (i.e., whether we could say "the capabilities a component has isn't a meaningful idea, it's just the capabilities a component routes that matters"), and what I've come to realize is that I still haven't really wrapped my head around the component model.

The main thing that breaks my brain is the distinction between a component's hard candy coating (i.e., the interface its realm exposes to its parent) and a component's creamy nougat center (i.e., "self", the running program that may implement some of that interface). Even that distinction isn't quite right, because there's also the interfaces the "center" offers and routes to the children, which are like... a crispy wafer layer? (I think this analogy is working great, thanks for asking.)

It brings me back to that idea of having "leaf components" and "routing components" as two separate concepts. It seems like that model would be a lot easier to understand, though that doesn't necessarily mean it'd be easier to use

I agree with Gabe, though. We need to start by being clear with our users and ourselves what the model actually is, and we need to let these ideas develop gradually over time. The most obvious fix (i.e., "derive the 'capabilities' section automatically in cmc") might not work, or it might just be a bandaid over a deeper issue. 

Hunter

Gary Bressler

unread,
Jul 13, 2021, 2:00:51 PM7/13/21
to Hunter Freyer, Gabe Schine, Rich Kadel, Shai Barack, component-framework-dev, Aaron Wood
Let me take a stab at an analogy :-)

Consider functions. A function has both an interface and implementation. A function may be an implementation detail of a program, or part of a library's public interface, or both. Functions may be declared in a program's 'top' namespace, or in a nested class. [1]

The declaration of a function is distinct from the implementation. Also, there are keywords you can use to control a function's visibility. For example in C++, public/private and friend. The place where a function's visibility is set is usually at the declaration, but not always -- for example, Rust lets you re-export identifiers with different visibility.

A capability is like a function. It has a declaration (the capabilities section) and a definition (the actual implementation). It may be part of the public interface (expose) and/or an implementation detail of the component (offer/use). For the purposes of this analogy, imagine a program is equivalent to a top-level class. The children are like classes in your program: they are in the end part of the same program, but there is nonetheless a definite boundary. offer is like dependency injection into those classes, via passing a particular implementation of a function. Classes, at least in some languages, can be nested, so your children can have children, etc. Finally, classes (components) can be reused between multiple programs (components).

Do a program's classes count as part of the program's interface or are they purely an implementation detail? It depends on your perspective. From the outside, the only parts that matter are those that are publicly exposed. But from the inside, a program is composed of interactions between a set of classes that define their own interface boundary through a set of functions. This observation remains true if you replace "class" with "component" and "function" with "capability".


[1] A submodule is another possible analogy, but I think a class works slightly better because it lets one draw a comparison to dependency injection.

Justin Mattson

unread,
Jul 13, 2021, 5:24:32 PM7/13/21
to Gary Bressler, Hunter Freyer, Gabe Schine, Rich Kadel, Shai Barack, component-framework-dev, Aaron Wood
My mental model for components has come to be that they are all interface and no implementation. This is, probably, a very component manager-centric view. A component is defined as a container. The component can sub-divide itself (ie. have children) and define how those sub-divisions connect amongst themselves and to the outside. They are a box with pipes sticking out which can define internal spaces which would fit a box-with-pipes with a specific pipe configuration. Whether a given pipe is fed by the box it comes out of or a box inside that box, <shrug>, at least from a component perspective.

From a use perspective things like "routing components" (which have no pipes feed from themselves, but instead all connected directly to interior boxes) create an adapter, an indirection.  A routing component's external pipe configuration always looks the same, but we might easily swap out different routing components in whose interior looks different (eg. external pipe A is welded to interior box 3, pipe 7).

I think separate routing and leaf components would be harder to use with CML as it is and without additional tooling. Swapping over to the class analogy, one of the things that drives my nuts about C[++] is the use of separate header files, which can contain implementation! In a similar vein, if I'm a child of some parent and I just want to find out where my offered capability is actually coming from, checking two places is a pain at best and at worst the routing component definition might be hard to find.

Reply all
Reply to author
Forward
0 new messages