Ad
  • Custom User Avatar

    Now I see what "tagless" means.

  • Custom User Avatar

    It seems my solution is a hack which translates the terms into ordinary terms in ADT after I read others' solutions. 😂

  • Custom User Avatar

    It seems compareTo is not necessary either. I simplified it a bit. What about this then?

    // The class `Fraction` is translated from the Java one.
    // Feel free to modify the code to be more concise and idiomatic in Kotlin as long as the function `fraction`'s type and the type `Fraction` are preserved.
    
    fun fraction(numerator: Long, denominator: Long): Fraction = TODO()
    
    class Fraction(var numerator: Long, var denominator: Long) {
        override fun hashCode(): Int =
            17 * numerator.hashCode() + denominator.hashCode()
    
        override fun equals(other: Any?): Boolean =
            other is Fraction && numerator * other.denominator == other.numerator * denominator
    
        operator fun plus(other: Fraction): Fraction = TODO()
    
        override fun toString(): String = TODO()
    }
    
    /* Or as an alternative, make Fraction an immutable data class and always reduced:
    data class Fraction(val numerator: Long, val denominator: Long) {
        operator fun plus(other: Fraction): Fraction = TODO()
    
        override fun toString(): String = TODO()
    }
    */
    
    
  • Custom User Avatar

    a function whose only purpose is calling the constructor

    In the val case its purpose can be adapted to also reduce the fraction. I believe this functional option is indeed necessary as I have explained in my first reply. So do you think it would be better if I make this function body a TODO()?

    a class with lots of poorly implemented boilerplate code (a very bad hashCode, and equalsTo which allows the fractions to not be reduced and introduces a vulnerability as tests rely on its implementation which you do not control)

    This is mainly because it's translated from the Java solution setup. hashCode is more a Java convention and I tested that the solution actually works even if you remove it. The equals issue remains in the solution setups in all other languages (C#, Haskell, Java, and Python). This is an inherited problem and if you think we should fix this maybe we should fix all other language versions first.

    a vulnerability as tests rely on its implementation

    And I don't think this is a vulnerability because this equals() works no matter the Fraction is reduced or not. It's just inefficient if the Fraction is always reduced.

    IMO, it'd be much better to change everything to this:

    As you have said, this is your opinion. Immutability in the functional way is also an alternative opinion. See Immutability in Coding Conventions. I think both opinions should be allowed.

    Let me show you the Haskell solution setup for example:

    module Fraction (Fraction, fraction) where
    
    data Fraction = Fraction Integer Integer
    
    fraction :: Integer -> Integer -> Fraction
    fraction = error "TODO: Fraction constructor"
    
    instance Eq Fraction where
      Fraction a b == Fraction c d = a*d == b*c
    
    instance Show Fraction where
      show = error "TODO: show minimal representation"
    
    instance Num Fraction where
      (+) = error "TODO: add fractions"
      (*) = undefined
      negate = undefined
      abs = undefined
      signum = undefined
      fromInteger = undefined
    

    As you can see, there is a fraction function and instance Eq Fraction also allows the fraction to not be reduced.

  • Custom User Avatar

    True. I had wasted a lot of time thinking what went wrong until I saw your comment. By convention, the minus sign is never placed in the denominator in a reduced fraction. I think this should be an issue rather than a suggestion.

  • Custom User Avatar

    It's true and that's why I added the following comment to the code

    These comments are pointless. Suggesting people to rewrite the code in a better way won't make them do so.

    from what I understand, you are trying the make the solution setup simpler to understand

    No, I think that you're making things uglier than they could be. Initial solution should provide a minimal setup for implementing the solution while you're providing:

    • a function whose only purpose is calling the constructor
    • a class with lots of poorly implemented boilerplate code (a very bad hashCode, and equalsTo which allows the fractions to not be reduced and introduces a vulnerability as tests rely on its implementation which you do not control)

    IMO, it'd be much better to change everything to this:

    // solution
    
    class Fraction(private var n: Long, private var m: Long) {
        val numerator: Long get() = n
        val denominator: Long get() = m
        
        init {TODO()}
        operator fun plus(other: Fraction): Fraction = TODO()
        override fun toString(): String = TODO()
    }
    
    
    // tests
    
    val f1 = Fraction(1, 8) + Fraction(4, 5)
    assertEquals(37, f1.numerator)
    assertEquals(40, f1.denominator)
    
    val f2 = Fraction(4, 8)
    assertEquals(1, f2.numerator)
    assertEquals(2, f2.denominator)
    
  • Custom User Avatar

    But the initial solution is a class, not data class, so all this "if I implement, if I make" talk is meaningless. Either declare Fraction a data class to do what you say and justify such design, or get rid of that function and let users do whatever they want in their code.

    It's true and that's why I added the following comment to the code:

    // The class `Fraction` is translated from the Java one.
    // Feel free to modify the code to be more idiomatic in Kotlin as long as the function `fraction` and the type `Fraction` passes the tests.
    

    Or a possible fixed and clearer version:

    // The class `Fraction` is translated from the Java one.
    // Feel free to modify the code to be more concise and idiomatic in Kotlin as long as the function `fraction`'s type and the type `Fraction` are preserved.
    

    Your invoke() solution does work but IDEA shows the following warning:

    Private primary constructor is exposed via the generated 'copy()' method of a 'data' class.
    

    Besides, doing this is more tricky and less idiomatic, and it requires the coder to be more familiar with the Kotlin language and might make this Kata more difficult than necessary. I don't think this is what this Kata is intended for and there is a Tricky Kotlin collection specially intended for this.

    Anyway, from what I understand, you are trying the make the solution setup simpler to understand, while I am trying the make the solution setup more cumbersome but it allows both beginner (those whose write Java-style Kotlin) and experienced Kotlin coders to work out their own solutions, both being reasonably difficult, and the latter one being more idiomatic. Both have their merits. If you insist on yours, we can make it so. Or we can decide by which one gets more votes.

  • Custom User Avatar

    If I implement the Fraction class whose both field are immutable, and I also make the class a data class

    But the initial solution is a class, not data class, so all this "if I implement, if I make" talk is meaningless. Either declare Fraction a data class to do what you say and justify such design, or get rid of that function and let users do whatever they want in their code.

    this is necessary... constructing data through other conversions should be defined with functions with explicit names

    Why can't you make you a data class like this?

    data class Fraction private constructor(val num: Long, val denom: Long) {
        companion object {
            operator fun invoke(n: Long, m: Long): Fraction {}
            
            // Alternatively:
            // fun create(n: Long, m: Long): Fraction {}
        }
    }
    

    Idk the Kotlin's best practices, but this looks like a decent solution to me - it does the same thing but all the logic is defined in the class now.

  • Custom User Avatar

    See my solution and the Haskell version. If I implement the Fraction class to represent only reduced fractions whose both field are immutable vals, and I also want to make the class a data class to eliminate the need to write hashCode and equals, this is necessary. This is more idiomatic as Kotlin promotes immutability and some other practical functional ideas. From the Haskell perspective, a data constructor is only directly called when its fields are explicitly given, and constructing data through other conversions should be defined with functions with explicit names, Kotlin is similar in this way. For example, to create a BigInteger from a s: String, s.toBigInteger() is preferred over BigInteger(s).

  • Custom User Avatar

    There's no point in having a separate fraction function.

  • Custom User Avatar
  • Custom User Avatar

    This comment is hidden because it contains spoiler information about the solution

  • Custom User Avatar

    This comment is hidden because it contains spoiler information about the solution

  • Custom User Avatar

    I have thought of a quicker algorithm but there are so many cases to consider and they are realy cumbersome! I can never think of all of them without the test cases. This is basically test-driven programming.

  • Custom User Avatar

    There used to be a translations for Java, Kotlin, Dart, etc... But these languages tends to be trickier than Haskell and one cannot guarantee the users understands the purpose of this Kata (in particular the unMaybe function, Java users used a lot of hacks to make them work). So I think at least my attitude towards Scala would be negative, sorry.

    As you can see the Java, Dart, Kotlin translations are already deleted.

  • Loading more items...