I’m trying to refactor GenericInstruments.jl in order to play nicer with instrument front panels GUIs for our online university labs.
The problem is the following: different instruments keep popping up and the code needs to be compliant with the interface defined for the GUIs.
For example, let’s say that a GUI for a power supply needs two methods: set_voltage(instr, val) and get_voltage(instr) in order to set the psu and to read it. The reality is not that simple for other instruments which have tens of methods.
How can I enforce development of a driver for a new instrument to be compliant with the necesities of the GUI? Let’s say a new contributor does this.
Should I tell him to go and implement all the methods described in the documentation? In Matlab there are abstract classed which you can inherit from: if you forgot to implement one of the methods defined in the abstract class it yells at you.
I am currently reading that book. I did look back at the interface implementation section and basically it boils down to: define function f(Any...) error("Should be implemented by the concrete type.") end and creating a test suite that can be called over a type to check if it implements the promised behavior (or, at least, does not throw that error message).
Well, I would not say that it is only that, but it is effectively something simple. Yet, I am not comfortable in just showing what the book says, since it is being sold almost for free… The author deserves some credit.
I previously solved this issue by simply providing a template file with empty functions for the person implementing the interface to fill in. It’s not very glamorous, but it solved the problem very effectively. It had the added benefit of making various implementations similar in terms of the file structure, making the code easier to navigate.
On a side note: my situation was also to provide implementations for university lab equipment, in my case for processes for automatic control
I also used this method in the past, it also worked as a rough documentation. Might give it a try again.
As for the lab, we’re using the GUIs mainly for debugging purposes, hoping the students still feel at least a bit connected to the hardware. The main purpose is to control the equipment remotely and teach them how large scale measurements are really done in the industry. Equipment changes, now I’m struggling to integrate the C++ library of ADALM2000
I didn’t read the book so I am not responding to that, but in general I don’t think that defining functions to just throw an error indicating that someone should implement a method is good practice, instead of just getting a MethodError — after all, that’s what it is for.
I guess it depends on how much you want to give your users training wheels. While it is probably not a good practice in general (meaning you always should do it if possible), I see no reason to consider it a bad practice in general either.
BinaryTraits.jl (from @tk3369 , the author of the book) has signature checking feature, it’s worth taking a look.
I was recently in the same situation, and ended up creating a separated test package where the code is in the src folder so it can be easily called from the tests of other packages. I am happy with it exactly because it also tests requirements that are not described in the signature.
Since there’s a reference about my book, I should probably voice my opinion
I think it depends on the intended usage and audience.
As a application developer, I may want to see a MethodError for missing implementations because it’s what I normally get when I make a mistake in my code and the quickest way to get to the problem.
As a user of some third-party package, I may want to see a nice error that says “oh, sorry, you have hit a bug. Please submit an issue at our github site XYZ”. I don’t consider this a good practice to let the users of your package receive these low-level method errors.
BinaryTraits.jl was created due to the lack of formal interface/traits support by the language. The problem that I intended to solve is to let the developer specify interface formally, and so an implementer of that interface can easily discover the interface requirements and verify the correctness of the implementation during unit testing.
I am happy to hear more perspectives about this matter.
Kind of lets you have your cake and eat it.
You can avoid the antipattern of NotImplementedException
which can give less clear and useful information than a MethodError (see that linked blog post for an example);
while still also being able to give a bit of an extra human readable hint about what is most-likely wrong.
I would not assume what you assume. Many libraries like JuMP are used by people that have very little knowledge of Julia and benefit from training wheels, many do not have reasons to learn the language deeply just to use the features they intend to use and I would find obnoxious to try to force them to learn more advanced concepts instead of pointing out they probably forgot a parentheses or something like that.
Also I would point out here that having formal interfaces is very useful when working larger projects. You can have many people developing different pieces. They aren’t going to know much about what are working on. Nor should they. You should expose a clear interface for them to adhere to so they don’t have to read your code. It should be immediately clear what to implement in order to adhere to the interface. This saves time and reduces bugs. Languages such C# sharp do this very well. Personally I love Julia but in the informal interfaces make very it frustrating reuse code that in poorly documented. ( of which there is a lot.) I find my self wasting hours reading code. However if interfaces was formal It would just tell you what need implement. Sure you get method errors but you don’t get that until run the code. Any way I like C# interface enforcement. I whish Julia has something similar.