w3c / activitypub

http://w3c.github.io/activitypub/
Other
1.22k stars 77 forks source link

strictly typed #312

Closed ppwfx closed 6 years ago

ppwfx commented 6 years ago

What's the general opinion on adding types to the properties?

I'm asking as I'm working on an en/decoder in golang and it's a pain having to implement it, as properties can have multiple types. It's an issue that all typed languages have, which leads to significant slower adaption.

Additionally it would be simpler to specify and document the behaviour of the properties.

A typed version could kinda look like this:

{
      "@context:[]string": [
        "https://mastodon.social/users/kiriska/statuses/100162061472548087/activity"
      ],
      "@context:[string]string": {
        "@vocab" : "https://www.w3.org/ns/activitystreams",
        "ext": "https://canine-extension.example/terms/",
        "@language": "en"
      },
      "@context:[][string]string": [
        {
          "@vocab" : "https://www.w3.org/ns/activitystreams",
          "ext": "https://canine-extension.example/terms/",
          "@language": "en"
        }
      ],
}
ppwfx commented 6 years ago

Or elevate all properties to the most verbose representation possible.

So instead of having:

"orderedItems": [
    "https://mastodon.social/users/aainsleyy",
    "https://mastodon.art/users/eecks",
]

You would have

"orderedItems": [
    {
      "type": "Link",
      "href": "https://mastodon.art/users/eecks"
    },
    {
      "type": "Link",
      "href": "https://mastodon.art/users/eecks"
    },
]

Having different objects in a Collection, is something you can easily built abstractions around. But having different representations of the same thing, in this case a link is super annoying.

Inside the application all the stuff needs to be mapped to an abstract representation again, if we want to be able to write generic SDKs.

ppwfx commented 6 years ago

Having something that's deterministic, would even allow to specify the api as sth like openapi.yaml or grpc definitions. Thus, allowing to simply generate SDKs for all languages.

gobengo commented 6 years ago

it's a pain having to implement it, as properties can have multiple types. It's an issue that all typed languages have, which leads to significant slower adaption.

This is at least the third issue filed by golang users while trying to deal with ActivityStreams2 data (really the concern applies to any profile of JSON-LD data). I am sorry it is so troublesome.

This issue motivated me to finally pull my TypeScript types out of distbin and into gobengo/activitystreams2, which other node.js/TypeScript users can use.

The types: https://github.com/gobengo/activitystreams2/blob/master/src/index.ts

I understand you can't use it directly, but I hope that some example of type definitions is illustrative to others like us going down this path.

I have used golang only a bit. From what I can tell, it is indeed very hard to model AS2 data in any typed language that does not support generics and union types, which golang community has implied will not soon be supported. I liu of that, your plan of expanding things into their most verbose form as early as possible is probably a good one (e.g. single-item values into arrays for nonfunctional AS2 properties, some string URL values into Link objects).

I have also been excited this week about gitpub, and seen your updates over too. Good luck on your work on this and other things. Hope to fed w/ you soon.

strugee commented 6 years ago

Also, a little note on W3C process - unfortunately, we can't make huge changes like this at this stage, when the spec is already published. It would break existing implementations in countless ways. Sorry :(

nightpool commented 6 years ago

I would note though that nearly all relationships in as2 are typed, they're just not types that are "written" in the document in the sense that your examples are. You can look at https://www.w3.org/ns/activitystreams.html for a little more information on the schema

On Fri, Jun 8, 2018 at 4:27 PM AJ Jordan notifications@github.com wrote:

Also, a little note on W3C process - unfortunately, we can't make huge changes like this at this stage, when the spec is already published. It would break existing implementations in countless ways. Sorry :(

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/w3c/activitypub/issues/312#issuecomment-395880681, or mute the thread https://github.com/notifications/unsubscribe-auth/AAORV9wIJ9BNHWo4_JhnJ3UKHVRic-h-ks5t6t4kgaJpZM4Uf2_r .

nightpool commented 6 years ago

You might also be interested in reading more about JSON-LD and how it acts as a serialization of RDF data https://json-ld.org/learn.html

cjslep commented 6 years ago

This difficulty is exactly why I use a code-generation method to make the golang ActivityStreams lib here: https://github.com/go-fed/activity

(vocab and streams subpackages)

cjslep commented 6 years ago

I am happy for other alternative golang libs to exist and have been meaning to write up the challenges and what I've learned from making it, so others can know the kinds of problems to tackle when designing their own implementations.

ppwfx commented 6 years ago

@gobengo I just skimmed through your implementation and I must admit I'm very jealous, didn't even know TS allows to overload types

@strugee yeah I figured, that's why I closed the issue

@nightpool cheers, that answers a lot of question, sorry Im a little knew in the semantic web world

@cjslep I think every implementation comes with a tradeoff and I think it's good to have a diverse set of implementation initially to get closer to an implementation that minimises the overall tradeoff surface in the long run

cjslep commented 6 years ago

I agree!

thosakwe commented 5 years ago

I have used golang only a bit. From what I can tell, it is indeed very hard to model AS2 data in any typed language that does not support generics and union types,

Union types are absolutely a necessity to work with ActivityStreams 2.0, though you can simulate them with polymorphism if a language doesn't support them. What really makes AS2 a pain in a typed language is if said language does not have JSON as a primitive. In TypeScript, it's easy, because JSON data from a server/client can be directly used as data, but if you have to deserialize it from a variety of different forms, even using a code generation tool is not very pleasant.

I ran into this when trying to implement ActivityPub in Dart (https://github.com/regiostech/activity_pub/blob/master/lib/src/models.dart). Dart has no union types, and also requires deserialization to read JSON. Creating an APObjectOrLink pseudo-union was no problem, but difficulties arose when that Object can actually be a subclass of Object, i.e. Actor.

I might have to be a bit smarter about my deserialization (i.e. using some handwritten code in addition to the generated code), but I do wish that it were a little more deterministic. I've wanted to get my hands dirty with ActivityPub for a long time, but having to do a server in JavaScript is a no-no for me (and probably many others).

cjslep commented 5 years ago

@thosakwe A word of caution: AS's "extending" is not the same as the object oriented concept of inheritance. Equating the two is a road to pain. For example, in ActivityStreams it is acceptable for a child type to only inherent a subset -- not all -- properties of the parent type being extended. See IntransitiveActivity for an example. I hit this exact problem when generating the types in Golang and don't want you to go through that pain point.

thosakwe commented 5 years ago

Thanks. I’ll probably end up writing a custom generator at the end of the day. Might end up writing a blog post about how to implement AP in a statically types language, as I can imagine it would certainly help others.

ppwfx commented 5 years ago

@thosakwe what's the overall objective of your undertaking?

I'm just asking as I went down a similar road a year ago and generating types from jsonld and populating them can evolve to a great amount of complexity.

I'm not sure how intensively engaged with jsonld so far, but to be on the safe side allow me to share two concepts I'd have like to have known before I gave it a try.

  1. Every field within a jsonld document refers to a property identifier that's defined within a context, which can be local or remote. To be able to mitigate name collisions, it's possible to alias these identifiers.

The following jsonld documents, are all valid jsonld and represent the same data and structure.

{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name",
  },
  "name": "John Smith",
}

{
  "@context": {
      "http://xmlns.com/foaf/0.1",
  },
  "name": "John Smith",
}

{
  "@context": {
     "thename":  "http://xmlns.com/foaf/0.1/name",
  },
  "thename": "John Smith",
}

Thereby a fully compliant implementation requires to normalize the jsonld before mapping it onto objects.

  1. Valid jsonld allows use a field identifier n-times, without specifying how it should be treated.
{
  "@context": {
    "name": "http://xmlns.com/foaf/0.1/name",
  },
  "name": "John Smith",
  "name": "Foo Bar",
}
thosakwe commented 5 years ago

Thanks for that explanation. That’s definitely a lot of complexity, so all in all, I might just implement my project first, and look into AP compat later.

On Wed, Sep 25, 2019 at 2:03 PM ppwfx notifications@github.com wrote:

@thosakwe https://github.com/thosakwe what's the overall objective of your undertaking?

I'm just asking as I went down a similar road a year ago and generating types from jsonld and populating them can evolve to a great amount of complexity.

I'm not sure how intensively engaged with jsonld so far, but to be on the safe side allow me to share two concepts I'd have like to have known before I gave it a try.

  1. Every field within a jsonld document refers to a property identifier that's defined within a context, which can be local or remote. To be able to mitigate name collisions, it's possible to alias these identifiers.

The following jsonld documents, are all valid jsonld and represent the same data and structure.

{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", }, "name": "John Smith", }

{ "@context": { "http://xmlns.com/foaf/0.1", }, "name": "John Smith", }

{ "@context": { "thename": "http://xmlns.com/foaf/0.1/name", }, "thename": "John Smith", }

Thereby a fully compliant implementation requires to normalize the jsonld before mapping it onto objects.

  1. Valid jsonld allows use a field identifier n-times, without specifying how it should be treated.

{ "@context": { "name": "http://xmlns.com/foaf/0.1/name", }, "name": "John Smith", "name": "Foo Bar", }

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/w3c/activitypub/issues/312?email_source=notifications&email_token=ACMIUPELFS7UHP74AGKYCPDQLORWFA5CNFSM4FD7N7V2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD7SZVRQ#issuecomment-535141062, or mute the thread https://github.com/notifications/unsubscribe-auth/ACMIUPFBO2BSA2KPA6BG5UDQLORWFANCNFSM4FD7N7VQ .

--

Tobe Osakwe Student, B.S. Comp. Sci, Florida State University https://thosakwe.com

ppwfx commented 5 years ago

you're welcome :)