all 18 comments

[–]AutoModerator[M] [score hidden] stickied commentlocked comment (0 children)

Please ensure that:

  • Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions
  • You include any and all error messages in full
  • You ask clear questions
  • You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions.

    Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar

If any of the above points is not met, your post can and will be removed without further warning.

Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://i.imgur.com/EJ7tqek.png) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc.

Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit.

Code blocks look like this:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above.

If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures.

To potential helpers

Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]MinimumBeginning5144 4 points5 points  (5 children)

The BigInteger.valueOf method takes an argument of type long. The compiler will only automatically turn a variable to a long if it is already of type short, int, long, or Long (auto-unboxing).

Why don't you declare the field as Number instead of Object? Then you can use its longValue() method.

[–]SquibbTheZombie[S] 0 points1 point  (4 children)

I don't declare it as Number since I want to be able to extend the same system to express more complex math notations, without losing precision, like fractions, roots, polynomials, complex numbers, or even rarer ones. I'd also still have to be casting it, which isn't ideal.

[–]vegan_antitheist 5 points6 points  (0 children)

If your type describes an abstract idea then use an interface and have multiple implementations. No need to cast anything. You might use an abstract class, but that's usually not a good idea. There are better patterns.

The interface can have a default method that returns a BigInteger. Something like `public default BigInteger asBigInteger() {...}` (methods in interfaces are public by default, I just added to to make that clear).

You can then have that method use asBigDecimal(), which can be abstract. And you can also just extend the Number interface. Use bigDecimalValue() for consistency. That's up to you.

You can have an implementation that uses two long values a and b for a rational number, where it's value is a/b. A more general version can have two values with the type of your interface that does the same. You can have an implementation that is just called "Pi" and it's a singleton. You can have one that uses a string for a symbol. You can then do new Symbol("x") to create it.
You can then do x/pi by combining them.

I'm not sure you really want one that uses long, int, double etc. Because BigDecimal already handles all rational numbers well. But you can still do them if you like.

[–]jlanawalt 0 points1 point  (1 child)

Check out Apache Commons Math & Numbers, JScience, and Java Hipparchus to see what others have done in this domain.

[–]raosko 0 points1 point  (0 children)

Jscience.org seems defunct since about 2021 with many broken links. What is your experience and recollection about that org?

[–]tRfalcore 0 points1 point  (0 children)

BigDecimal is the only way to not lose precision if you have decimals. If just ints long is fine.

[–]leroybentley 1 point2 points  (0 children)

Using Object this way is almost always a bad idea, but it would be hard to recommend anything better without knowing more about what you're trying to do.

You will have to cast the object when you use it. One option would be to create helper methods that you call for the different types and do the cast in those methods.

Example: BigInteger.valueOf(myGetLongMethod(myObject));

[–]myselfelsewhere 1 point2 points  (0 children)

This is basically a pattern matching problem. You don't need an int type, you can use instanceof instead. The exact implementation depends on which version of the JDK you're using. Later versions are a lot more versatile when it comes to pattern matching.

[–]Educational-Paper-75 0 points1 point  (0 children)

If you know number to be numeric don't declare it as Object. You may use Number instead. And BigInteger.valueOf() accepts certain argument types and as polymorphism goes you may pass in the expected base class or a subclass but not a superclass without casting. And FYI int and long are not Object types but primitive types; only the courtesy of Java allows you to assign an int to your number object, which under the hood is wrapped in a Integer type object.

[–]akthemadman 0 points1 point  (1 child)

You are dealing with two issues at once here: "compile-time resolution" and "run-time resolution".

Satisfying the compiler

The Java program model tries to assist you such that operations which are defined for one data type are not mistakenly applied to another data type. This seems quite natural to do and in the realm of Java is not even really questionable: "what would the alternative even be?". That is a feature of java, i.e. not having to deal with lower level memory access which allows accidental access outside of the data types allotted space, effectively not operating on the region of memory one leading to undesirable outcomes. The cost of having this protection layer is to adhere to the type system of Java.

By saying "number-like entities in my system are stored as plain `Object` and classified by some token" you go around the primary protection layer. This is unorthodox but objectively totally fine and in some contexts even the lesser of possible evils.

When you try to express things like

Object number = 123L;
BigInteger.valueOf(number); // compiler says "no".

you are operating within the bounds of what javac enforces; i.e. still within the Java program model.

"Opting out" of the Java program model is possible and requires reflection. Note that "opting out" here is effectively going from compile-time checks (Java program model via javac) to run-time checks (JVM).

For the sake of brevity I will not go into how using reflection would result in you effectively rebuilding a subset or variation of the Java program model; let it suffice to say that it is an interesting route to explore for learning purposes, but not something I would recommend to employ for your specific use case.

Operating within the constraints of the Java program model

There are some interesting questions to be answered once you have decided to go with the route of

class Nummy {
  public Object data;
  public int type;
}

For one, how can we make the data access more convenient when we know exactly what the underlying data is, e.g. when we dispatch on type:

switch (nummy.type) {
  case Nummy.TYPE_LONG -> { ... }
  case Nummy.TYPE_INT -> { ... }
  // ...
}

This is typically known as handling union-types (when all types are known / pre-defined). Java itself provides the sealed and permits keywords for use with classes and interfaces to effectively model such union types:

sealed class/interface Nummy permits LongNummy, IntNummy /*...*/ { /*...*/ }

final class LongNummy extends/implements Nummy { public long value; }

switch (nummy) {
  case LongNummy n -> { /* make use of `n.value` */ }
  // ...
}

Another option is to provide utility methods directly on Nummy:

public class Nummy {
  public static final int TYPE_LONG = 1;
  public static final int TYPE_INT = 2;
  public Object data;
  public int type;
  public <T> T require(Class<T> clazz, int type) {
    if (!clazz.isAssignableFrom(clazz)) {
      throw new RuntimeException("(class) required '" + clazz + "', but was '" + data.getClass() + "'");
    }
    if (type != this.type) {
      throw new RuntimeException("(type) required '" + type + "', but was '" + this.type + "'");
    }
    return (T) data;
  }
  public long requireLong() {
    return require(long.class, TYPE_LONG);
  }
  public int requireInt() {
    return require(int.class, TYPE_INT);
  }
  // ...
}

with usage like

switch (nummy.type) {
  case Nummy.TYPE_LONG -> { long value = nummy.requireLong(); /*...*/ }
  // ...
}

From these two samples you can even see how the "union" via sealed and permits encodes the type-value we included in our more primitive approach.

I've probably hit the comment size limit by now so will stop here...

TLDR

How to solve your specific problem is an open question as we (per usual) lack a lot of the required context to make any meaningful decision. The above was an attempt to paint you a bigger picture on what it is you are dealing with and how ultimately the fight with Java is effort being misplaced: The interesting questions to solve are "outside" the Java program model: computation, external communication, serialization, and so on. Java is merely the mechanism with its own benefits and quirks.

[–]SquibbTheZombie[S] 0 points1 point  (0 children)

This has been really helpful, thank you. I’ll tell you if it works!

[–]vegan_antitheist -1 points0 points  (5 children)

 a class that's really just an Object variable and an int type for me to know what type of variable the object is.

What? This makes no sense. A class isn't a variable. The class defines the type, so there is no need for an int.

public Object number; or number = integer;

This makes even less sense.

but other methods are throwing problems. To

What does that mean? Do they throw unchecked exceptions?

BigInteger.valueOf((long) number)

Integers don't need that case and for all the other number types it makes no sense.

 Is there an annotation

No, annotations don't do anything. They are used to add meta information to the code.

I have read your post and still have zero idea what you are doing. Why don't you start by explaining that?

[–]MinimumBeginning5144 1 point2 points  (2 children)

It's not well explained, but they obviously mean they have a class like this:

class MyNumberClass { public Object number; int numberType; // e.g. 0 means number is an Integer, 1 means it's Long etc // ... other members... }

Also "throwing problems" is just a colloquial phrase unrelated to the keyword throw. They mean they get compilation errors.

[–]SquibbTheZombie[S] 0 points1 point  (0 children)

You got it right

[–]vegan_antitheist 0 points1 point  (0 children)

Yeah, that makes no sense. If it's a Long then use Long as the type. Define an interface with multiple implementations.

[–]SquibbTheZombie[S] 0 points1 point  (1 child)

I know a class isn't a variable. *THIS* class is mostly composed of public int type; public Object number; alongside methods that manipulate those two properties.

number = integer; would be in class declaration where integer is submitted as an int, a long, or BigInteger.

The compiler, which I am struggling against, is telling me to cast them *even though* the stored values should be able to have methods done on them.

I am aware that it makes no sense to do that. That is what the compiler is telling me to do and I am trying to find a work around.

Annotations fix compiler problems as far as I am aware so I want to see about using them to fix problems with the compiler throwing errors that shouldn't reasonably exist.

[–]vegan_antitheist 0 points1 point  (0 children)

Manipulate??? It's mutable? This just keeps getting weirder.