You used a FFI attribute that can't be used with @send

Hi all,

I received the following error:

You used a FFI attribute that can't be used with @send

FAILED: cannot make progress due to previous errors.
>>>> Finish compiling(exit: 1)

After I tried to create a method function for addEvent like this:

type track
type event
module MidiWriter = {
    @module("midi-writer-js") @new external track: unit => track = "Track"
    @module("midi-writer-js") @send external addEvent: (track, event) => unit = "addEvent"
}

I have no clue how to fix this error, any ideas?

You don’t need the @module attribute on the @send binding, as the addEvent isn’t imported but held in your object of type track

1 Like

Hey!

You can’t mix @module with new @send. First you need to factor out the new binding into your own external, which is then used together with your @send bindings.

Here is a full port of the midi-writer-js README example:

// MidiWriter.res

module Event = {
  type t

  @new @module("midi-writer-js")
  external programChangeEvent: {"instrument": int} => t = "ProgramChangeEvent"

  @new @module("midi-writer-js")
  external noteEvent: ({"pitch": array<string>, "duration": string}) => t = "NoteEvent"
}

module Track = {
  type t
  @module("midi-writer-js") @new external make: unit => t = "Track"
  @send external addEvent: (t, Event.t) => unit = "addEvent"
}

module Writer = {
  type t
  @module("midi-writer-js") @new external make: (Track.t) => t = "default"

  @send external dataUri: t => string = "dataUri"
}

let _ = {
  let track = Track.make()

  let change = Event.programChangeEvent({"instrument": 1})
  track->Track.addEvent(change)

  let note = Event.noteEvent({"pitch": ["C4", "D4", "E4"], "duration": "4"})
  track->Track.addEvent(note)

  let write = Writer.make(track)
  write->Writer.dataUri->Js.log
}

Playground Link

Hope that helps getting the point across!

1 Like

Is this correct? :thinking: Maybe you meant mixing @module and @send?

BTW, maybe a more precise error message could help? I can create an issue, but where? The syntax repo or the compiler repo?

Oops, thanks for that… edited my post.

This should be reported on the compiler repo

2 Likes

Amazing, thank you.
It’s a conceptual challenge to master this.

I only had to change the line
@module("midi-writer-js") @new external make: (Track.t) => t = "default"
to
@module("midi-writer-js") @new external make: (Track.t) => t = "Writer"

What’s most amazing is that the generated javascript looks exactly as the original from the README example, except for the added exports and indentation.

2 Likes

@ryyppy old post so dont know if the api has changed. Just tried running this and got

src/MidiWriter.bs.js:32
var write = new MidiWriterJs(track);
            ^
TypeError: MidiWriterJs is not a constructor;

We should post a working version for others who might come through looking for binding examples. I will do so if you or @ronen dont do it first.

Peace!