Groovy oo

Does Hubitat’s groovy implementation support classes? ST didn’t.

+1 excellent question.

Can you expand on what you are asking? I don't quite understand the question.

class Person {
    String name
}

I'm still not sure of the question. But if you are asking if you can define an inner class in a Groovy script, then the answer is no.

That answers it and is what I thought.

Bummer.

1 Like

What are you trying to do that you need to define additional classes? Perhaps the community can suggest a different solution for you.

I already did it without classes, it would be cleaner with them. I’m good.

I concur - being able to define classes for behavior is a must-have for writing code of any complexity. Some DTHs are hundreds of even 1000+ lines.

I'm reopening this thread after a very long time, but...

I have "OO-ish" code working in Hubitat. It's not true classes, but it's based on how things were done in Javascript back in the day. Basically, we have a dynamic language... sooo... why not attach methods to a Map?

Here's an example "class" definition:

// ***************************************************
// **** Class Definition - Person
// ***************************************************

def person_Constructor(String pName = "Unknown", Number pAge = -1) {    // Strong typing and default values
// Ability to have extra logic in the Constructor
if (pAge == -1) {
    pAge = 0
}

// The instances of the class that are returned by the Constructor are actually Groovy Maps.
def instance = [
    name: pName,
    age: pAge
]

// Dynamically attach closures to the Map instance for getters/setters/methods
instance.setName = { n -> instance["name"] = n }
instance.setAge = { a -> instance["age"] = a }

instance.getName = { return instance["name"] }
instance.getAge = { return instance["age"] }

instance.sayGoodbye = { log.debug "Goodbye ${instance.name}!" }

// Return the instance from the Constructor
return instance
}

Then, to use it in a driver or app:

// Constructor can have parameters
def person1 = person_Constructor("John", 41)

def person2 = person_Constructor("Susan", 43)
person2.setName("Bob")        // Using a setter to overwrite values from the constructor
person2.setAge(44)

// Using the default parameters of the constructor
def person3 = person_Constructor()

// Call getters on the class instance
log.debug "Person 1's values are ${person1.getName()} ${person1.getAge()}"
log.debug "Person 2's values are ${person2.getName()} ${person2.getAge()}"
log.debug "Person 3's values are ${person3.getName()} ${person3.getAge()}"

// Call a method on the class instance
person1.sayGoodbye()
person2.sayGoodbye()
person3.sayGoodbye()

Caveats and Notes:

  • It's main benefit is encapsulation. It's not perfect. You could access map members directly. But the benefit here of having "classes" isn't so much in safety as it is in being able to think in abstractions.
  • I have not demonstrated inheritance in this example. It could be done. I can see how it could be done. However, I don't think I'll need it for what I want to use this for. (Encapsulating abstractions)
  • It has a tiny bit of type-safety on the constructor, but no overall safety on the class itself. So I guess polymorphism "works" but I wouldn't recommend it.
  • Basically, since we can't do real classes, this is use-at-your-own-risk code to at least get encapsulation and the idea of instances that have both data and methods.
  • Ok, why do I want encapsulation so badly? Well, I'm writing an app that has some subtle state change logic. The logic itself is not very complicated, but running through all my test scenarios with the code talking to real devices was time-consuming and prone to errors. I want to be able to separate out my logic layer from my device interaction layer, and write unit and integration tests.
  • There's still no re-use between different apps and drivers.
  • Final LOL: Now I'm imagining something like TypeScript. A compiler that can turn real Groovy classes into something like this for use in Hubitat. I will leave this as an exercise for the reader.
3 Likes

Reminds me of creating 'classes' in Lua.