Input: Lying about typing?

I'm writing an application. In mainPage(), I have an input line...

input (name: "cHours", type: "integer", title: "<b>Hours before now</b>:", defaultValue: 24, submitOnChange: true, width: 3)
This is returning cHours with the correct value but apparently wrong type... In the following call, cHours is the fourth parameter...

groovy.lang.MissingMethodException: No signature of method: java.lang.String.call() is applicable for argument types: (java.lang.Integer, java.lang.Integer, java.util.Date, java.lang.String) values: [200, 200, Wed Jul 10 16:58:12 PDT 2024, 24]

The method being called has the signature:

String build(Integer width, Integer height, Date endTime, Integer hours) 

You can see it is correctly "24". Without the quotes.
Changing my code to passing cHours.toInteger() rather than cHours fixed it.

I have a hard time believing this is correct; that "input" asks for type and returns a string anyhow. What might I be doing wrong?

This is not a valid value for the type parameter. Presumably you meant "number" or perhaps "decimal", which should fix your problem.

See also:

2 Likes

That's not a valid type for input, try "number".

2 Likes

Thank you, both. It would be nice if "input" had it's own page, but also...

  1. "number" is apparently a "java.lang.Long", not an "integer", which is a deal-breaker to Groovy.
  2. Why would it be "number: Integer" and not have an alias for Integer to "number"? This seems like unnecessary pedantry.

For #1, emitting "log.trace "cHours is type ${typeOf(cHours)}"
returns: cHours is type Long

Which, in Groovy, seems to be an incompatible type to Integer.

Should I be using a type "number" for these in Groovy?

Most people do not use any typing in groovy code which actually drives me mad. I have found it to be more agreeable to sometimes just give in an use type 'Number' (instead of Integer) for function definitions when you are not sure of or cannot easily control the exact type being sent over.

You can also pass it to the function as (cHours as Integer) which I know is what you were trying to avoid. I have found casting with 'as Type' is a little safer than using the .toType() methods.

As an alternative: why not make your build() function take a Long instead? You made it, you make the rules. :slight_smile: If you do get an Integer, Groovy (or I think this really from Java) will also automatically widen.

But yes, as mentioned above, dynamic typing is pretty common Groovy. This can be convenient, and for small apps or drivers doesn't really matter too much. It's common even in larger apps, but I normally find code easier to read if it's a bit more explicit -- largely a matter of preference (and possibly performance if your app is large, but if you aren't writing webCoRE or Rule Machine it's not likely to be significant).

1 Like

Can I just say, without offending you, that this is absolutely idiotic? The docs say number == Integer. So, first, "integer" should work, and second, "number" -> "integer" rather than "long" should work?

Again, no offense intended, but why make this so much harder than it has to be? It's not like there's a good IDE for it.

For reference, I do have a lot working. This is the current working-output - a 24-hour temperature graph, done 100% locally. Need a lot of touch-up work, but really, it's not like I'm some po-dunk know-nothing developer. Types should just work and just work correctly.
(I'm not really as annoyed as that sounded.)

2 Likes

The short answer, not that you were necessarily looking for one: the system is based on one that favored dynamic typing, and the goal of significant compatibility. That is still an option for you today if you prefer.

I can review the docs, however.

So the answer is, Hubitat can't document right, can't do typing right... so to do proper dev for Hubitat, you must ignore all good practices, develop at the level of a pathetic script-kiddie, and it will work?

That's actually pretty offensive. Let's review.

  1. "Integer" is not an accepted "type" for input, but, and this is an actual quote, "number: Integer"
  2. But... number is NOT an Integer. Number is a long
  3. And the Hubitat solution is, WTF, dude knows how to program!!!! No way!!!! Just use def!
  4. Which, BTW (or FN Way)... is much less efficient.

I'm a fan of Hubitat. I came over from Samsung SmartThings. As poor @bobbyD can vouch, I have an early early early C5, although now on a C8P. But dudes, this is whack.

Fix the docs. If "number==long", just say so. And make a page for Input specifically, or create aliases for "long", "integer" (which y'all apparently think == long), etc.

It's not hard. Please just do it. Because I'm trying to build cool stuff.

1 Like

Documents are written by humans who sometimes makes mistakes. In this case, it was a capital letter where there shouldn't be, and it's already fixed. The intent is to note that it denotes an integer in the mathematical sense, not Integer specifically.

An explanation of one valid value does not mean that the literal explanation itself is a valid value...

Lots here, but: Groovy is intentionally a dynamic language -- this is one of its notable features and part of reason it was created. For real-world examples outside of the hub, look at a Grails app and you'll see a lot of def (this is probably the most popular use of Groovy, and def is more or less required in many cases due to varying types that may be encountered). For an example closer to home, look at any classic ST DTH and you'll see the same, this, of course, being the environment that inspired Hubitat's.

While it is trendy among some developers on Hubitat to use static types or something in between, it's not "poor practice" to use the dynamic features Groovy was very much created to have. The previous comments still stand about the difference for most apps and drivers on the hub. And it doesn't mean anyone says you're a bad programmer, can't write good apps or drivers, or anything else.

2 Likes

Thank you. I do find the dynamic typing problematic for doing such math-intensive work with (the allowed) Java libraries. In such cases, those errors would simply get pushed further down into the more opaque Java stack, making it harder to find.
Would you please add to the docs the actual type returned also? e.g. "number: long integer" ?

1 Like

Yeah I agree, I try to avoid the dynamic typing because it just causes me more frustration later when you pass something wrong, or try to math on a String.

I have learned though for system function calls (like command buttons from capabilities) to just leave the parameters untyped and expect to get anything, and check it right away if it needs to be a certain type. Had one that should have come in as a number (and I had it defined as such) but the dashboard was sending the button number as a string so it broke my driver.

2 Likes