Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

feat: add flow annotations#27

Open
garrensmith wants to merge 3 commits into
multiformats:masterfrom
garrensmith:add-flow
Open

feat: add flow annotations#27
garrensmith wants to merge 3 commits into
multiformats:masterfrom
garrensmith:add-flow

Conversation

@garrensmith

Copy link
Copy Markdown

This adds flow annotations to multihashing.

This is part of ipfs/js-ipfs#1260

This adds flow annotations to multihashing
Comment thread .babelrc
@@ -0,0 +1,34 @@
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having this file (.babelrc) and .flowconfig, could we have these in a separate repository and import here? Would be a lot better, otherwise this is gonna be duplicated everywhere.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ideally we should move these into AEgir

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly .flowconfig isn't js or json so you can't really pull it from elsewhere (unless you're thinking of git submodules which aren't worth the hassle IMO).

As of .babelrc indeed this probably should end up in AEgir.

@garrensmith

Copy link
Copy Markdown
Author

The tests will fail until multiformats/js-multihash#47 is merged in since I use some of the types based off of that PR.

@vmx

vmx commented Apr 3, 2018

Copy link
Copy Markdown
Member

I hope that it's still possible without too much hassle. Could you please use prettier-standard, it matches the current code style better. I would also suggest to make it two separate commits. First the prettier-standard run without any other changes and then the commit with the actual annotation and tooling changes?

Comment thread .babelrc
@@ -0,0 +1,34 @@
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly .flowconfig isn't js or json so you can't really pull it from elsewhere (unless you're thinking of git submodules which aren't worth the hassle IMO).

As of .babelrc indeed this probably should end up in AEgir.

Comment thread src/blake.js Outdated
}

var blake2s = {
blake2b.init(1, 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this init call intended here ? I don't see it in original code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry that was a mistake. I was testing the flow checking.

Comment thread src/blake.js
}

var i
// I don't like using any here but the only way I could get the types to work here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other way to do it would be to add another table in js-multihash which would be {[number]:Code} and then do const code = thatTable[minB + i]. That being said it's probably fine the way it is here.

Comment thread src/index.js Outdated
import * as crypto from "webcrypto"

const mh = module.exports = Multihashing
const mh = (module.exports = Multihashing)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest export default Multihashing

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I had export default Multihashing but that changes the api of this library for commonjs because instead of doing const multihashing = require('multihashing') a user now have to do const mh = require('multihashing').default which I don't think we want to do with the initial flow conversion.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@garrensmith In fact flow-node babel preset takes care of this as it includes add-module-exports plugin only thing to watch out for is that you can either single default export or multiple non default exports (as there is no way around it with common-js style).

Comment thread src/index.js Outdated
}

mh.createHash = function (func, length) {
mh.createHash = function(func: Name | Code): Hash {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is aside comment more on the API design. I would very much encourage to either have two different functions one that works with codes the other with names or better yet settle on canonical representation and make coercion a consumer's concern. The fact that IPFS libs tend to take unions of things made by far most difficult to figure out what's being passed around (although types would solve this) and also choose representation to use myself.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vmx I think we should open up an issue around this. Something that could be added in another PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Please open issues if you find weirdness in the API. Adding types is surely a good reason to review the APIs.

Comment thread src/sha3.js
digest(): Sha3Hash {
if (!this.input) {
throw Error("Missing an input to hash")
}

@Gozala Gozala Apr 3, 2018

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I would really recommend encoding such invariants in a type system as primary benefit of type checking is to eliminate possibility of runtime errors. I don't know exact specifics of how this is used so my specific suggestion may not necessarily be applicable here, but it might still clarify what I mean. Usually such invariants can be encoded at the type level by making invalid state unrepresentable. Here is an example:

interface HashUpdate {
  update(buf: Buffer): Hash;
}

interface Hash extends HashUpdate {
  digest(): Buffer;
}


class ShaHash implements Hash {
  // Assumbtion is that this static function is exposed and not the class so that consumer can only create
  // HashUpdate and can't create `Hash` without an input. Since our `HashUpdate` interface does not have
  // a `digest` attempt to call will be reported by a type checker.
  static new(hashFunc, arg?: number):HashUpdate {
    return new ShaHash(hashFunc, arg)
  }
  // Since `update` returns a `Hash` that has both `digest` and `update` methods
  // calling `digest` on returned value will be by fine by type checker. Please also note
  // that even though it's the same instance from type checker perspective former still
  // has not `update` and later does.
  update(buf: Buffer): Hash {
    this.input = buf
    return this
  }
  // It is necessary to check this as `input` can be `null` but either way it's useful to cover
  // consumers that don't use type-checker
  digest(): Sha3Hash {
    if (!this.input) {
      throw Error("Missing an input to hash")
    }
    //...
  }
}

Comment thread package.json
"dependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those 3 are devDependencies aren't they?

Comment thread package.json
"flow-copy-source": "^1.3.0",
"lint-staged": "^7.0.2",
"pre-commit": "^1.2.2",
"rollup.config.flow": "^1.0.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as multiformats/js-multihash#47 (review). No need for rollup I guess.

Comment thread src/blake.js
}

var i
// I don't like using any here but the only way I could get the types to work here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More out of curiosity - what was the problem? Shouldn't Code be just an alias for number?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were opaque type aliases which behave like nominal types. In that module context any number can be treated as Code but outside of that context Code is a subtype of number and only way to get hold of value of that tipe is by getting it from that module either from exposed constant annotated as Code or via function that returns Code. This gives you a way to say have parseCode : number -> ?Code function that can return passed value back but ensuring that it’s a valid Code. Kind of typically you’d have isCode function but such that type checker then enforce typings

@daviddias daviddias added the status/deferred Conscious decision to pause or backlog label Aug 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

status/deferred Conscious decision to pause or backlog

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants