33

I am used to developing in Python, but for work reasons have to do it in Java. I am facing a task that would be trivial in Python, and I'd like some advice on how to handle this in Java the proper way.

I need to parse a duration string. It can be in milliseconds (235ms) or seconds (32s). And it can also be "< 1ms" as a special case.

The parsing happens at least three times in the code so I'd like to separate it into a method. But my code does need to know, not just the resulting value in ms, but also whether it was in ms or s and whether it was <1ms (0 is a different value).

In Python I would just return a tuple:

return (value_in_milliseconds,is_in_seconds,is_under_1ms)

In C I would define a struct of these three values and return it. In Pascal I'd define a record.

In Java I can't return a tuple and I can't define a record so what do I do?

The only thing I can think of is creating a class representing a duration value. The constructor would take the string and parse it. The class would have fields: int milliseconds, boolean inSeconds, boolean under 1ms .

But this sounds terribly heavyweight - is there a better solution?

candied_orange
  • 7,036
  • 2
  • 28
  • 62
Mikhail Ramendik
  • 1,063
  • 2
  • 12
  • 26
  • 16
    How is defining a class in Java any more heavyweight than defining a "record" (I assume you mean struct) in C? – Chris Hayes Apr 25 '17 at 19:43
  • 3
    @ChrisHayes In C you can allocate a struct on the stack for temporary use and the function would take a pointer. C might also let you return a struct by value. (I'm not sure. C++ can do it.) – Radiodef Apr 25 '17 at 19:47
  • 3
    @ChrisHayes sorry, I mixed up my languages, edited post. And honestly I am more concerned about code size and readability as opposed to memory use (that's why I like Python). A struct of three fields is just 5 LOC. A class is a file with a lot of boilerplate in it. – Mikhail Ramendik Apr 25 '17 at 19:52
  • 1
    There are ways to eliminate the boilerplate - notably with the use of Lombok - but essentially you're trading the convention and familiarity of Java for the conventions and familiarity of another language. At some point, you're going to have to write Java. – Makoto Apr 25 '17 at 19:55
  • 11
    I would recommend that you fix your design to return the ms only. Whoever is calling that method in its current state has a lot of work to do to understand the result. – njzk2 Apr 26 '17 at 15:18
  • 3
    I agree with @njzk2. Ideally, I'd expect that method to return a time span (`java.time.Duration`?). At a high level, you're converting a string to an amount of time, why not use an object that makes that explicit? Or you could simply normalize it to milliseconds (or smaller) and then perform the checks for `is_in_seconds` and `is_under_1ms`. – Harrison Paine Apr 26 '17 at 16:13
  • @HarrisonPaine given a duration of 1000ms, how do you perform the check for `is_in_seconds` which would tell you whether the original string was "1s" or "1000ms"? – Pete Kirkham Apr 26 '17 at 16:20
  • 1
    @PeteKirkham Well, `is_in_seconds` is a property of the input, not the represented timespan. The whole design seems a little convoluted honestly. – Harrison Paine Apr 26 '17 at 16:40
  • 1
    Can the input be something like 345,000ms ? Or the "ms" type of the string will always be under 1s? – Mindwin Remember Monica Apr 26 '17 at 18:21
  • The OP may have constructed this example rather than explain the intricacies of their problem domain. Anyway, 'problem' is that Java (and other strongly typed languages) have their own perspective. Languages like Python and Ruby and Javascript let you do these things because they approach problems from a different perspective. – ChuckCottrill Apr 27 '17 at 07:00

10 Answers10

26

Don't pass around a set of flags that must be consistent between them to make a sensible state. What if is_in_seconds and is_under_1ms are both true? And why would a variable that contains the word milliseconds ever be interpreted as seconds? How wrong-looking that will be in the code. Wrong-looking code is not good if you can do anything about it--we're supposed to write code whose appearance of rightness/wrongness matches reality—the Principle of Least Astonishment applied to code, and perhaps even the Pit of Success for subsequent developers whose brains will explode on that.

This sounds like maybe a bit of the Primitive Obsession code smell/antipattern, perhaps from your Python background? (I know next to nothing about Python so feel free to disregard this guess.)

Solution: make a real domain-level object that represents the idea of an approximate duration.

One possible implementation of that:

  1. Create a DurationScale enum that has members Second, Millisecond, SubMillisecond.

  2. Create a class ApproximateDuration, that takes a duration integer and a durationScale enum value.

  3. Now consume this object in your other code. If you need to sum a series of these durations, make a class that knows how to interpret each one and add them together. Or add methods to this class.

An alternative to some concept like DurationScale could be MarginOfError which can be expressed in some arbitrary number of milliseconds, itself. This could allow you to use a strict mathematical formula to increase the margin of error appropriately as you sum different ApproximateDuration objects together into a new ApproximateDuration object.

Note: You can see some further discussion on why I recommend this approach.

The implementation you settled on is also a good way to handle it, where you explicitly state the lower and upper bounds:

public final class ApproximateDuration {
   private final int lowMilliseconds;
   private final int highMilliseconds;

   public ApproximateDuration(int lowMilliseconds, int highMilliseconds) {
      this.lowMilliseconds = lowMilliseconds;
      this.highMilliseconds = highMilliseconds;
   }

   public int getLowMilliseconds() {
      return lowMilliseconds;
   }

   public int getHighMilliseconds() {
      return highMilliseconds;
   }
}

Note that putting the word Milliseconds in the variables and property names is important, as is the immutability of this class.

ErikE
  • 48,881
  • 23
  • 151
  • 196
  • 2
    This answer combined with the others has finally let me find the right solution - which turned out completely different and, yes, more Java-ish too. I now have a duration class where I store the minimum and maximum in milliseconds, and the constructor is a parser and another constructor takes no arguments and makes a 0. It also has an in-place Add method (taking another object of the same type), so it can be an accumulator - I could override addition, but an accumulator seems more resource-effective. And finally it has a Compare method returning boolean. This was quite a ride, thanks everyone! – Mikhail Ramendik Apr 27 '17 at 15:14
  • Yes, that's exactly what I was talking about. The Add and Compare methods are perfectly legitimate implementations. Glad I could help. – ErikE Apr 27 '17 at 17:11
  • Note: [Java does _not_ allow operator overloading](http://stackoverflow.com/q/1686699/1347968). – siegi Apr 30 '17 at 06:39
  • @siegi Thanks for the correction. – ErikE Apr 30 '17 at 14:27
22

It's no different than a C struct but you'll somehow at the least end up inheriting from Object

class Blah {
   public String value_in_milliseconds;
   public String is_in_seconds;
   public String is_under_1ms;
}
user253751
  • 57,427
  • 7
  • 48
  • 90
jiveturkey
  • 2,484
  • 1
  • 23
  • 41
  • ...and have it as a private class within a class? Might actually work best, thanks! – Mikhail Ramendik Apr 25 '17 at 20:53
  • I'd move the body of the parse method into the constructor of this class, and consider turning these fields into get-only properties – Caleth Apr 26 '17 at 12:02
  • Yeah a POJO would be ideal if he were using it throughout his program as a DAO or whatever but if he just needs a simple return I wouldn't bother. Sometimes OO principles are just that, principles. I'd do what he suggests and make it a (nested) private class. – jiveturkey Apr 26 '17 at 15:27
  • 2
    Yep, this is the way to go. Do make it a private *static* class within the class. (Consult *Effective Java* 2e, Item 22.) If necessary, package-private is fine. It must not be public. – wchargin Apr 27 '17 at 01:52
  • @wchargin unless it will must be public, which will likely happen at some moment, so the one minute you saved by creating private class without getters and setters instead of POJO will cost you at least one hour refactoring, recompiling, redeploying and testing. – 9ilsdx 9rvj 0lo Apr 27 '17 at 11:51
  • 4
    You probably don't want to use `String` types for this – milleniumbug Apr 27 '17 at 12:39
15

Define your own class or use for example apache commons:

return Triple.of(value_in_milliseconds, is_in_seconds, is_under_1ms);
maszter
  • 3,680
  • 6
  • 37
  • 53
  • 4
    I find this to be the most pragmatic answer. Java has generics - there's nothing stopping somebody from defining a few Tuple classes (with various numbers of type arguments) that can be used for situations like this. – KChaloux Apr 26 '17 at 12:29
8

I tried with a below example of passing a Object[] instead, keeping it simple:

public class MultiWayTest
{
    public static Object[] send() {
        return new Object[] { 1002322, false, true };
    }

    public static void main(String[] arg) {
        Object[] recieve=send();
    }
}

You may have noticed the statement return new Object[] { 1002322, false, true };

Hope that helps

izrik
  • 918
  • 2
  • 9
  • 20
Roshan
  • 667
  • 1
  • 5
  • 15
  • Wow. The equivalent of a Python Tuple, the Java way, much neater than aly library Tuple implementations! But, how do I retrieve the results? In your example, if I want to read the second value (false), is it recieve [1]? recieve.get(1)? – Mikhail Ramendik Apr 26 '17 at 13:45
  • recieve[0] will give 1002322 , recieve[1] will give false etc , recieve is basically an array , treat it like one and do necessary casting when retrieving the elements, if need be. – Roshan Apr 26 '17 at 13:58
  • 2
    Not "basically" an array, it **is** an array. But you'll have to cast to the appropriate (object) types: `(Integer)receive[0]`, `(Boolean)receive[1]` (from there auto-unboxing can convert to the primitive types) – user253751 Apr 26 '17 at 22:38
  • 2
    I downvoted this answer because an array is not at all the right solution. It requires boxing of primitive values, casts that cannot be inserted by the compiler, and magic array indices—unless you declare them as constants, in which case you might as well just do it right and create a data class. – wchargin Apr 27 '17 at 01:53
  • @wchargin Magic array indices ? I am still a novice – Roshan Apr 27 '17 at 03:17
  • 2
    @roshanmathew: I mean that the numbers `0`, `1`, and `2` are "magic numbers" in the following sense. If I want to access the field `isUnder1Ms`, I use `arr[2]`. There is no logical connection between `2` and `isUnder1Ms`. In other words, instead of field names, you are forced to use the "names" `0`, `1`, and `2`. A simple typo will mean that your code does the wrong thing (changing `2` to `1`, say) instead of not compiling (changing `isUnder1Ms` to `isUdner1Ms`, say). – wchargin Apr 27 '17 at 03:51
  • Thanks for the explanation , so it is more on the lines of coding practices – Roshan Apr 27 '17 at 04:10
  • @wchargin but this is exactly as good (or as bad) as the Python example from the OPs question. If your religion makes you hate that solution, downvote the question and not the correct answer to that question. – 9ilsdx 9rvj 0lo Apr 27 '17 at 11:53
  • 1
    @9ilsdx9rvj0lo: Nope: in Python, you can immediately destructure the result, with `(x, y) = my_function()`. No magic indices required. Furthermore, the languages are different: in Python, returning tuples is something that is "done", and in Java this is simply not the case. – wchargin Apr 27 '17 at 12:18
  • @wchargin but this is a syntax sugar and not a real difference. In both languages, x and y would be something not fully specified. – 9ilsdx 9rvj 0lo Apr 27 '17 at 13:01
7

Personally, I'd do:

class Duration {
    final int millis;
    final boolean specifiedInSeconds;
    final boolean under1ms;

    Duration(String s) {
        // parsing logic
    }
}

This solution is reasonably short, allows the compiler to detect typos in field names, encapsulates the invariant that the booleans may not both be set, and may safely be shared with other code without risking aliasing bugs.

meriton
  • 68,356
  • 14
  • 108
  • 175
  • How does it encapsulate the invariant that the booleans may not both be set> While I actually went with an enum instead of booleans for the particular task, I would really like to understand how this would work. – Mikhail Ramendik Apr 26 '17 at 23:56
  • 3
    I think meriton just means that the constructor sets the Booleans, and then no one else can set them incorrectly. – Mark VY Apr 27 '17 at 04:13
  • Exactly. final fields can only be assigned in a constructor, and if the constructor establishes the invariant, nobody can break it. – meriton Apr 27 '17 at 16:09
4

You've hit exactly upon the Java way of handling this: You create a class to represent the answer, usually called a POJO (Plain Old Java Object). It's just a class with private members to hold each field, a constructor, getters, and optionally, setters.

That said, there are libraries that introduce Tuples or Tuple-esque abstractions, but they all work on POJO implementations.

Scala, which I also develop in, runs on the JVM, can interop with Java libraries, and has tuples among its many many other features.

Justin Reeves
  • 1,148
  • 10
  • 24
4

Separation of concerns

Your method returns a duration. It should not care whether the caller wants to have a special flag for <1ms durations, (which would be 0ms, I assume?) or to have to test if you return seconds or milliseconds.

I assume you have a flow that looks like this:

def main():
  val, is_s, is_0 = get_duration()
  if is_0:
    print "Less than 1 ms"
  elif is_s:
    print str(val) + " s"
  else:
    print str(val) + " ms"

def get_duration():
  # ...
  ms = # some value computed elsewhere, presumably in ms
  if ms > 1000:
    return (ms / 1000, true, false)
  elif ms < 1:
    return (ms, false, true)
  else:
    return (ms, false, false)

What you are doing here is putting your presentation logic in your getting method.

I would rewrite it like that:

def main():
  ms = get_duration()
  if ms > 1000:
    str(val / 1000) + " s"
  elif ms < 1:
    print "Less than 1 ms"
  else:
    print str(ms) + " ms"


def get_duration():
  # ...
  ms = # some value computed elsewhere, presumably in ms
  return ms

That way get_duration doesn't have to presume how the information is going to be used by the caller.

What if someone needs minutes and hours, too? You would have to re-write all your calling methods to accomodate for the change in the shape of the tuple. Better to just let the caller handle that.

njzk2
  • 38,969
  • 7
  • 69
  • 107
  • Well, the reason for the caller wanting the original time units is that a sum of some other durations get verified as equal to this duration, and I need to allow for rounding artefacts (it is a test of a UI). If the duration was in seconds, rounding artefacts can be up to 0.5 seconds (I'll probably even allow up to 1 seconds). If it was in milliseconds, then rounding artefacts can be up to 1 ms (I'll allow 2 ms). – Mikhail Ramendik Apr 26 '17 at 17:20
  • so the flow is really much different. I can't seem to be able to put code with newlines in a comment, but it is (1) parse a total duration, calculate rounding min and max (2) parse several durations and sum them up and (3) test that the sum is within the calculated mix-max. (In (2), durations of <1ms work by increasing the max by 1 s instead). – Mikhail Ramendik Apr 26 '17 at 17:22
  • @MikhailRamendik Yes, I figured that your use case might be a little more complex than that :) – njzk2 Apr 26 '17 at 17:46
  • (my previous comment has "by 1 s" at the end, should have "by 1 ms") – Mikhail Ramendik Apr 26 '17 at 17:54
  • I guess there could be some normalization before the output, like `if res < 1: res = 1`, and `if res > 1000: res = 1000 * round(res/1000)` – njzk2 Apr 26 '17 at 17:58
  • This is a good answer and I was looking for this exact idea on the page because I agree with the main point. For what it's worth, I've made my own answer that uses Mikhail's new information to suggest what I think is an even better implementation. – ErikE Apr 27 '17 at 02:16
3

I have Three ways in which you can solve this problem. As you mentioned you don't want the correct method which is my first choice. Using POJO (Plain Old Java Objects). And I know you will like third choice because that's my favorite.

1. Using POJO

Using pojo you say that you are strongly suggesting to return only specified properties in Class and nothing more.

public class DataObjectClass {

private String value_in_milliseconds;

private boolean is_in_seconds;

private boolean is_under_1ms;

public String getValue_in_milliseconds() {
    return value_in_milliseconds;
}

public void setValue_in_milliseconds(String value_in_milliseconds) {
    this.value_in_milliseconds = value_in_milliseconds;
}

public boolean Is_in_seconds() {
    return is_in_seconds;
}

public void setIs_in_seconds(boolean is_in_seconds) {
    this.is_in_seconds = is_in_seconds;
}

public boolean Is_under_1ms() {
    return is_under_1ms;
}

public void setIs_under_1ms(boolean is_under_1ms) {
    this.is_under_1ms = is_under_1ms;
}

public static void main(String[] args) {
    DataObjectClass dataObjectClassFromMethod = anyMethod();
    System.out.println(dataObjectClassFromMethod.getValue_in_milliseconds());
    System.out.println(dataObjectClassFromMethod.Is_in_seconds());
    System.out.println(dataObjectClassFromMethod.Is_under_1ms());
}

public static DataObjectClass anyMethod() {
    DataObjectClass dataObjectClass = new DataObjectClass();
    dataObjectClass.setValue_in_milliseconds("value");
    dataObjectClass.setIs_in_seconds(true);
    dataObjectClass.setIs_under_1ms(true);
    return dataObjectClass;
}
}

In above code snippet, I have created another class DataObjectClass, which will hold combined data. Now whenever I need multiple data from any method. I will create Object of that class in that method. I will set properties of object. Now I will return that object from method. Obviously return type of method is DataObjectClass. Even though it sounds heavy this is correct way to do it. For example you might need more information then you can't use tuple. You can also use Lombok annotation to reduce your code. You can get Lombok.jar and include it in your build path.

@Data
public class DataObjectClass {
    private String value_in_milliseconds;

    private boolean is_in_seconds;

    private boolean is_under_1ms;
}
public static void main(String[] args) {
        DataObjectClass dataObjectClassFromMethod = anyMethod();
    }

    public static DataObjectClass anyMethod() {
        DataObjectClass dataObjectClass = new DataObjectClass();
        dataObjectClass.setValue_in_milliseconds("value");
        dataObjectClass.setIs_in_seconds(true);
        dataObjectClass.setIs_under_1ms(true);
        return dataObjectClass;
    }
}

2. JSONObject

There is one more way to do it, you can use JSONObject.

public class JSONExample {

    public static void main(String[] args) throws JSONException {
        JSONObject data = anyMethod();
    }

    public static JSONObject anyMethod() throws JSONException {
        JSONObject data = new JSONObject();
        data.put("value_in_milliseconds","value");
        data.put("is_in_seconds",true);
        data.put("is_under_1ms",true);
        return data;
    }
}

3. HashMap

You can also use HashMap of String and Object, read more about accessing HashMap, HashMap is part of JDK so no external jar required. With HashMap you can do cool things. And this is the easiest way.

public class HashMapExample {

    public static void main(String[] args) {
        Map<String,Object> data = anyMethod();
    }

    public static Map<String,Object> anyMethod()  {
        Map<String,Object> data = new HashMap<>();
        data.put("value_in_milliseconds","value");
        data.put("is_in_seconds",true);
        data.put("is_under_1ms",true);
        return data;
    }
}
  • 12
    Okay, I get it that it's normal in Java to spend tens of lines to make things conform. It is a hard transition from Python where such solutons are strongly discouraged. But at least could you tell me why in the POJO solution you have all the setters and getters? Why not just read the fields? The POJO class is a whopping 47 LOC. The setters and getters are 24 LOC, exactly half of that. How does this make the code any more maintainable or readable when it just expands it? – Mikhail Ramendik Apr 25 '17 at 20:49
  • re HashMap - did not think of this one - but as I understand I will have to use typecasting. It is currently a tie between this one and the nested class, which simply emulates a C struct. – Mikhail Ramendik Apr 25 '17 at 20:59
  • 1
    So in order to make code readable and maintainable you have lombok. third party library. Which instantly removes all getters, setters etc. If you think you will update fields in future or add extra fields, I will suggest you to use HashMap(JDK) or JSONObject(org.json) JSONObject will be helpful in handling nested objects more gracefully. – mr.dev.null Apr 25 '17 at 21:00
  • 5
    The setters and getters are likely overkill, a class with public fields is likely the better choice. The HashMap and JSONObject are not typesafe, and suspectible to typos. Oh, and please use Java naming conventions (camelCase rather than snake_case) when naming fields or methods. – meriton Apr 26 '17 at 21:24
  • 8
    I downvoted this answer because the HashMap "solution" provides the worst of all worlds. It is stringly typed instead of strongly typed; it requires unsafe casts that cannot be inserted by the compiler; it forces boxing of primitive types; it is not amenable to refactoring or static analysis; it requires hashing strings; it requires using string literals—unless you declare them as constants in a class made for this purpose, in which case you may as well just do it the write way and add three fields. – wchargin Apr 27 '17 at 01:51
  • (And, lest it need saying, the JSONObject solution has all the same pitfalls and more.) – wchargin Apr 27 '17 at 01:55
  • @MikhailRamendik The point is that in strict OOP, everything is virtual. A consumer of your return value should also handle any other object that conforms to the same interface. And since fields cannot be virtual, they should always be private. Java style builds a lot on OOP, so this heavy-weight approach is usually preferred, even though Java-as-a-language doesn't make it exactly easy (e.g. in C#, you could write `public bool IsInSeconds { get; set; }` and it creates the accessors and the backing field). Mind you, I'm not *endorsing* this approach, just explaining it :) – Luaan Apr 27 '17 at 09:14
  • 1
    @meriton public fields are a terrible choice, making your DTOs incompatibile with almost anything. Almost all Java utilities require POJOs with getters and setters. Calling something 'overkill' because it requires a few mouse clicks is a real overkill. – 9ilsdx 9rvj 0lo Apr 27 '17 at 11:58
  • 1
    Downvote because the solution is way too complicated. And you didn't even define POJO... which more specifically I would call a "bean" where you just left the default constructor. – Douglas Held Apr 27 '17 at 16:20
3

You wrote:

The only thing I can think of is creating a class representing a duration value. The constructor would take the string and parse it. The class would have fields: int milliseconds, boolean inSeconds, boolean under1ms .

This is close to what I'd do by not exactly what I'd do.

I'd introduce a parameter object whose constructor is ParseResult(String valInMS, boolean isInSeconds, boolean isUnder1MS). Then I'd add a public static ParseResult parse(String) method that calls the constructor and returns the result.

By the way, in your example it looks like you want to consider using a java.util.Duration object.

Ivan
  • 1,256
  • 1
  • 9
  • 16
  • I have looked up java.util.Duration but unfortunately it does not seem to store the original time units. And that is a requirement in my case. Also, its parser does not seem to accept values like "300ms" or even "P300ms". – Mikhail Ramendik Apr 26 '17 at 13:50
3

Creating a new class here is indeed annoying, but this is mostly forced on you by the fact that Java is statically typed and Python is not. (EDIT: not quite, see comment below.) If you're willing to give up the benefits of static typing, then one of the answers given here (the array of Objects) gives you pretty much what you had in Python. The ergonomics are not quite as nice as Python because callers of your method will need to use explicit casts, but if there are only 3 callers then maybe in some situations it's worth it to avoid defining a class. I don't think this is one of those situations, because if you actually count how many lines things take, most of the lines are taken by parsing, in both languages. To wit:

def duration(d):
  if d == '<1ms': return 0, False, True
  if d.endswith('ms'): return int(d[:-2]), False, False
  return int(d[:-1])*1000, True, False

4 Lines of code to deal with 3 cases. Not bad. I'm not sure I like this from a caller's perspective since I have to keep straight the order that Booleans go in, so you probably want to spend an extra line or two on a good docstring. Now let's do Java.

class Duration{
  int ms;
  boolean isInSeconds, isUnder1ms;
  Duration(String d){
    if(d.equals("<1ms")) isUnder1ms = true;
    else if(d.endsWith("ms")) ms = new Integer(d.substring(0, d.length()-2));
    else {
      isInSeconds = true;
      ms = 1000 * new Integer(d.substring(0, d.length()-1));
  }
}

Okay, that took 11 lines instead of 4. Clearly, Java is more verbose than Python. But let's try a detailed cost breakdown. Two of those lines are just braces, since Java doesn't use indentation. The last else clause took 3 lines because Java doesn't have Python's delicious string slicing features. Finally, there is the overhead of creating a class. That's another 3 lines or so. But notice that those 3 lines actually buy us a benefit over the Python code: the code sites are now self documenting! Compare:

dur = duration(d)
if d[2]: print 'it was in seconds' # or was it d[1]?  I forget.

with

Duration dur = Duration(d);
if(dur.isInSeconds) System.out.println("It was in seconds");

If you don't care about the benefit of self-documenting callers, you can use roshan mathew's answer. But note how little code it saves you, and how much you still have to write.

Mark VY
  • 1,489
  • 16
  • 31
  • 1
    This is definitely not forced upon you by static typing. In Haskell you could easily say `func s = (value_in_milliseconds,is_in_seconds,is_under_1ms) where ...` or far better yet, make it correct by construction with `data ApproxTime = SubMillisecond | Milliseconds Int | Seconds Int deriving (Show,Ord,Eq); duration ((=="<1ms") -> True) = Just SubMillisecond; duration (stripSuffix "ms" -> Just str) = Milliseconds <$> readMay str; duration str = fmap Seconds $ stripSuffix "s" str >>= readMay` Same 4 lines as the Python, more safety than the Java. Even cleanly handles malformed strings. – Steven Armstrong May 05 '17 at 03:09
  • good point, added disclaimer – Mark VY May 05 '17 at 18:51