Interface: MethodError: no method matching

I’m reading the book Hands-on-Design-Patterns-and-Best-Practices-with-Julia
in Vehicle.jl

module Vehicle

# ------------------------------------------------------------------
# 1. Export/Imports
# ------------------------------------------------------------------
export go!, land!

# ------------------------------------------------------------------
# 2. Interface documentation
# ------------------------------------------------------------------
# A vehicle (v) must implement the following functions:
#
# power_on!(v) - turn on the vehicle's engine
# power_off!(v) - turn off the vehicle's engine
# turn!(v, direction) - steer the vehicle to the specified direction 
# move!(v, distance) - move the vehicle by the specified distance
# position(v) - returns the (x,y) position of the vehicle
# engage_wheels!(v) - engage wheels for landing.  Optional.
# has_wheels(v) - returns true if the vehicle has wheels.

# ------------------------------------------------------------------
# 3. Generic definitions for the interface
# ------------------------------------------------------------------
function power_on! end
function power_off! end
function turn! end
function move! end
function position end

# soft contracts
engage_wheels!(args...) = nothing

# trait
has_wheels(vehicle) = error("Not implemented.")

# ------------------------------------------------------------------
# 4. Game logic 
# ------------------------------------------------------------------

# Returns a travel plan from current position to destination
function travel_path(position, destination)
    return round(π/6, digits=2), 1000   # just a test
end

# Space travel logic
function go!(vehicle, destination) 
    power_on!(vehicle)
    direction, distance = travel_path(position(vehicle), destination)
    turn!(vehicle, direction)
    move!(vehicle, distance)
    power_off!(vehicle)
    nothing
end

# Landing
function land!(vehicle)
    engage_wheels!(vehicle)
    println("Landing vehicle: ", vehicle)
end

# Landing (using trait)
function land2!(vehicle)
    has_wheels(vehicle) && engage_wheels!(vehicle)
    println("Landing vehicle: ", vehicle)
end

end # module

in FighterJets.jl

module FighterJets

export FighterJet

"FighterJet is a very fast vehicle with powerful weapons."
mutable struct FighterJet

    "power status: true = on, false = off"
    power::Bool 

    "current direction in radians"
    direction::Float64

    "current position coordinate (x,y)"
    position::Tuple{Float64, Float64} 

end

# Import generic functions
# I modify the code 
include("./Vehicle.jl")
import .Vehicle: power_on!, power_off!, turn!, move!, position

# Implementation of Vehicle interface

function power_on!(fj::FighterJet)
    fj.power = true
    println("Powered on: ", fj)
    nothing
end

function power_off!(fj::FighterJet)
    fj.power = false
    println("Powered off: ", fj)
    nothing
end

function turn!(fj::FighterJet, direction)
    fj.direction = direction
    println("Changed direction to ", direction, ": ", fj)
    nothing
end

function move!(fj::FighterJet, distance) 
    x, y = fj.position
    dx = round(distance * cos(fj.direction), digits = 2)
    dy = round(distance * sin(fj.direction), digits = 2)
    fj.position = (x + dx, y + dy)
    println("Moved (", dx, ",", dy, "): ", fj)
    nothing
end

function position(fj::FighterJet)
    fj.position
end

end # module

when I try to use it as fellos:
(in the same path, and in a file Try,jl)

include("./Vehicle.jl")
include("./FighterJets.jl")

# after 1.4 need to add .
using .Vehicle
using .FighterJets

fj = FighterJet(false,0,(0,0))
go!(fj,:mars)

it reports

ERROR: MethodError: no method matching power_on!(::FighterJet)

so I add a line to the FighterJets.jl

export power_on!, power_off!, turn!, move!, position

But it doesn’t work.

  • 1 What’s wrong?
    Maybe I misunderstand about the path, the module, the scope and the mutidispatch?
  • 2 is the code
function power_on! end

in module Vehicle is a way to remind/constrain that we must implement the power_on! function in anther place.

Try it without using .Vehicle since this is already imported in FighterJets.jl, but instead bring go! into the Main namespace as:

# Try.jl

# include("./Vehicle.jl")
include("./FighterJets.jl")

# after 1.4 need to add .
# using .Vehicle
using .FighterJets: FighterJet, Vehicle.go!

fj = FighterJet(false,0,(0,0))
go!(fj,:mars)

Yes, that’s the basic idea.

1 Like

thx so much, it works!
More confusion:

  • 1 However, this design is to make the following modules have to implement these functions, so is it a bit strange that it needs to be exported in this way(using .FighterJets: Vehicle.go!)? What should the best practice look like?

More confusion:

  • 2 the author provide the source code in github of this chapter3, The structure looks like as follows:
    image

the link is
and the author use code as follows to run it:

using Vehicle, FighterJets

fj = FighterJet(false,0,(0,0))
go!(fj,:mars)

Again, it doesn’t work,
In this way, they are two customized independent pkgs, How to using they together?
May be I can use activate? but it seems only support one pkg in one folder(either activate Vehicle folder or activate FighterJets folder).

Here’s how I think this is meant to be run:

  1. Clone the repo e.g.
$ git clone https://github.com/PacktPublishing/Hands-on-Design-Patterns-and-Best-Practices-with-Julia.git
  1. Change to the chapter directory and run julia from there:
$ cd Hands-on-Design-Patterns-and-Best-Practices-with-Julia/Chapter03/

:../Chapter03$ julia --project=.
  1. In the Julia REPL, go to package mode ]:
(Chapter03) pkg> dev FighterJets
(Chapter03) pkg> dev Vehicle

Then you can run the code:

julia> include("4_interface.jl")
Powered on: FighterJet(true, 0.0, (0.0, 0.0))
Changed direction to 0.52: FighterJet(true, 0.52, (0.0, 0.0))
Moved (867.82,496.88): FighterJet(true, 0.52, (867.82, 496.88))
Powered off: FighterJet(false, 0.52, (867.82, 496.88))

? @tk3369

1 Like

amazing! I never considered that I should use the dev command instead of activate. What’s the difference between them? Is there any references that can help me understand dev better?

https://pkgdocs.julialang.org/v1/managing-packages/#Adding-a-local-package

1 Like

How about this question? I would like to ask you to recommend more material on how to organize the julia code.

This repository example shows the best practice. Have named projects containing modules in files within a src folder, a Project.toml file in the root of the project folder, and load modules using dev commands during development.

thanks a lot. I now know that what I need to read is the documentation of Pkg , and I didn’t realize it before, have been looking in the official manual

1 Like