Some background:
In MicroPython there is a class called Pin which controls I/O pins. In CircuitPython a similar class is called DigitalInOut. So for compatibility I wrote this simple class. Unfortunately, something goes wrong with my implementation. after calling:
drv_enn = PinC(board.D0, PinC.OUT)
drv_enn.on()
the pin doesn't go into 3.3V, but rather into 3.51V, which seem to be the uninitialized value. but this code does work, taking the pin into 3.3V:
drv_enn = DigitalInOut(board.D0)
drv_enn.direction = Direction.OUTPUT
drv_enn.value = True
so when I implemented a class without inheritance, it worked ok. My conclusion is that calling super().__init__(pin) did not work well. Did I do something wrong?
BTW I don't think that it is relevant, but my hardware is Seeed XIAO RP2040
my problematic implementation:
class PinC(DigitalInOut):
OUT = Direction.OUTPUT
def __init__(self, pin, mode=Direction.OUTPUT):
super().__init__(pin)
self.direction = mode
def on(self):
self.value = True
def off(self):
self.value = False
def read(self):
return self.value
This class works as expected - without inheritance:
class PinC:
OUT = Direction.OUTPUT
def __init__(self, pin, mode=Direction.OUTPUT):
self.dio = DigitalInOut(pin)
self.dio.direction = mode
def on(self):
self.dio.value = True
def off(self):
self.dio.value = False
def read(self):
return self.dio.value
I'd be glad to find out what is the root cause for this!
Related
Premise:
I want to separate the information necessary to instantiate a class from the information necessary to "run" the class. However, the information neccesary to "run" the class may differ from class to class. Thus, I imagine the class "has" specific information to run it, and the two go together.
Here is an example of my code:
trait Machine {
type Params <: BaseParams
def start(machineParams: Params): Unit
}
trait BaseParams {
def speed: Int
def power: Int
}
class FlyingMachine() extends Machine {
type Params = FlyingParams
override def start(machineParams: Params): Unit = {
println(s"I'm flying with $machineParams")
}
}
trait FlyingParams extends BaseParams {
def height: Int
}
abstract class MachineOwner{
val machine: Machine
def params: machine.Params
def startMachine(): Unit = {
machine.start(params)
}
}
This compiles, passes tests, I'm happy.
Problem: I'm using val machine: Machine in order to define def params: machine.Params. I've been told to make this a def to let the implementer have more freedom. If I do so, I can no longer refer to machine.Params
At this point, I'm at a loss for how to continue. I keep thinking that if this should be a def and definitely not a val, then my architecture is wrong.
So
Is my approach to this problem wrong, given the premise I set out with?
If it's not wrong, is there a way to still achieve this while using def instead of val in the MachineOwner class?
EDIT
Given Alexey Romanov's answer, the last bit of the code would look like this
abstract class MachineOwner{
type Params1 <: BaseParams
def machine: Machine { type Params = Params1 }
def params: Params1
def startMachine(): Unit = {
machine.start(params)
}
}
class FlyingMachineOwner(
machine: FlyingMachine
) extends MachineOwner {
override type Params1 = FlyingParams
override def params = FlyingParams(1,1,1)
}
But this doesn't compile because it expects an override specifically for def machine: Machine { type Params = Params1 }. How does one define that?
It really can't be answered without knowing desired semantics.
If MachineOwner is supposed to own a single machine, then "to make this a def to let the implementer have more freedom" is bad advice: the freedom it gives is exactly to return different machines from different calls to def machine and not to hold references to machines it gives out.
If it is supposed to have multiple machines, should all of them have the same Params type? Then you would do something like
abstract class MachineOwner{
type Params1 <: BaseParams
def machine: Machine { type Params = Params1 }
def params: Params1
def startMachine(): Unit = {
machine.start(params)
}
}
Or if not, then you need a different design again, maybe def params(machine: Machine): machine.Params. Etc. etc.
For the edit: you can do
class FlyingMachineOwner(
_machine: FlyingMachine
) extends MachineOwner {
override type Params1 = FlyingParams
override def params = FlyingParams(1,1,1)
override def machine = _machine
}
but it really seems unnecessarily complicated compared to what you get with type parameters.
I am trying to create a facade for the bootstrap popover function that can take up to 11 optional parameters. In my scalajs code I would like to only pass in the parameters I need to override from library maintained sensible defaults ie: PopoverOptions(animation = false) just like I would do in javascript. This seems to be the recommend way to make a facade but it makes all the parameters required:
trait PopoverOptions extends js.Object {
val animation: String = js.native
val container: String = js.native
val content: String = js.native
...
}
object PopoverOptions {
def apply(animation: String, container: String, content: String, ...): PopoverOptions = {
js.Dynamic.literal(animation=animation, container= container, content = content, ...).asInstanceOf[PopoverOptions ]
}
}
It looks like one way is to define an apply for every possible permutation of parameters but when there are lots of override parameters this gets excessive quick:
def apply(animation: String): ...
def apply(container: String): ...
def apply(animation: String, container: String): ...
...
What is the idiomatic way to create an options parameter facade with lots of override parameters that typically have sensible library maintained defaults?
Note: both answers have pros/cons so to decide it might be helpful to see both ways without leaving SO so here is a summary of JSOptionBuilder method:
import org.querki.jquery.JQuery
import org.querki.jsext._
#js.native
trait PopoverOptions extends js.Object
object PopoverOptions extends PopoverOptionBuilder(noOpts)
class PopoverOptionBuilder(val dict:OptMap) extends JSOptionBuilder[PopoverOptions, PopoverOptionBuilder](new PopoverOptionBuilder(_))
{
def animation(v:String) = jsOpt("animation", v)
def container(v:String) = jsOpt("container", v)
def content(v:String) = jsOpt("content", v)
...
}
To use: PopoverOptions.animation("yay").container("container").content("bottom")._result
You can use Scala's default values for parameters, combined with js.UndefOrs of the types of elements, like this:
object PopoverOptions {
#inline
def apply(
animation: js.UndefOr[String] = js.undefined,
container: js.UndefOr[String] = js.undefined,
content: js.UndefOr[String] = js.undefined,
...): PopoverOptions = {
val result = js.Dynamic.literal()
animation.foreach(result.animation = _)
container.foreach(result.container = _)
content.foreach(result.content = _)
...
result.asInstanceOf[PopoverOptions]
}
}
Then you can call with PopoverOptions(animation = false), as you wished.
It's a bit verbose at definition site, but it will get the job done.
The alternative approach is to use JSOptionBuilder, which was created for this purpose. (I write many jQuery facades, and they always have this problem.) JSOptionBuilder isn't quite as critical as it used to be (this was a major problem before the "|" operator was introduced), but I still find it's usually the best way to deal with complex facades.
Here's the full description of this approach. (Note that that's enormously detailed -- the first half is the key stuff, and the rest deals with all the somewhat-common edge cases.)
Consider this:
import packageName.doType._
class Worker
{
def doSomething(doType: DoType): Unit =
{
if(doType == Default) //...
}
}
Same file
object DoType extends Enumeration
{
type DoType = Value
val Default, Special = Value
}
Now as soon as I added the if(doType == Default) line I get two errors:
"==" cannot be resolved and suddenly "Value" in the DoType is not found anymore -.-
How can I check on the actual value of doType? I can solve the same very easily with (case-)classes, but I wanted to do it with enumerations.
edit: I already know that one cannot do pattern-matching on the type as it is a def and no val, still: How would you do this then?
The problem is in this line:
def doSomething(doType: DoType): Unit
IMHO it should be:
def doSomething(doType: DoType.Value): Unit
Is there any possibility to implicitly forward some of class methods to encapsulated object?
case class Entity(id: Int, name: String,) {
private lazy val lastScan = new LastScan
def getLastScanDate = lastScan.getLastScanDate
def updateLastScanDate = lastScan.updateLastScanDate
}
I want to avoid creating def updateLastScanDate = lastScan.updateLastScanDate just to forward methods to wrapped object.
In the plain language this is not possible. There used to be a compiler plugin by Kevin Wright to achieve this automatic delegation.
He seems to be working on an Autorproxy "Rebooted" version now that is macro based, making it straight forward to include in your project. I'm pasting here an example from its test sources:
trait Bippy {
def bippy(i : Int): String
}
object SimpleBippy extends Bippy {
def bippy(i: Int) = i.toString
}
#delegating class RawParamWrapper(#proxy pivot: Bippy)
val wrapper = new RawParamWrapper(SimpleBippy)
assert(wrapper.bippy(42) == "42")
I have a small conundrum when it comes to Scala properties.
Various blogs and tutorials tell me that this:
class Something
{
var foo = 1
}
...can be specified as...
class Something
{
private var _field = 1
def foo = _field
def foo_(foo: Int) = _field = foo
}
This makes perfect sense to me, when doing assignment the compiler looks for a name_ method. Problem is it doesn't seem to work for me.
In the following real-world code (same thing happens in other classes as well):
class Camera
{
private var _position = Vector2.zero
def position: Vector2 = _position
def position_(position: Vector2) =
{
// Do boring transforms.
_position = position // position shadows outer scope so this does work.
}
}
// ...
val camera = new Camera
camera.position = Vector2(10, 0)
I get an error:
error: value position_= is not a member of Camera
camera.position = Vector(10, 0)
Instead I need to call it the following way to actually make it work: camera.position_(Vector2(10, 0)) which is neither beautiful nor readable.
In other scenarios, for example when trying to have public getters and private setters I faced the same problem.
What am I doing wrong?
Using scalac 2.8.0 on Java HotSpot VM 1.6
Your setters need to be named foo_= and position_=. If you name them foo_ and position_ the compiler doesn't recognize them as setters.
The signature to implement is:
def position_=(position: Vector2): Unit
So you want to correct your code like this:
def position_=(position: Vector2) { _position = position }