TODO app in Kotlin

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
6
down vote

favorite












I'm learning Kotlin and I made a todo program (in command line) with Kotlin and Maven as my build tool.



Full project.



Description



The idea of my program is to read a file (path defined in a config file) that contains the list of tasks.



Since it's a project for practice purpose, the content of the file is quite simple and looks like this:



foo;true
bar;false
foobar;true


2 columns:



  • Description of the task

  • Status of the task

The only actions I've created are the following:




  • list the tasks (on the standard output)


  • add a new task (by writing a new line on the file)


  • finish a task (by setting the status of the task to true)

There are also other options:




  • help: display the list of options in the standard output


  • config: use another configuration file


  • verbose: display the debug logs


  • version: display the version of the program

The code



I'm using commons CLI library to help me parse command line options passed in the arguments.



I represented a task with the following:



class Task(var name: String, var isDone: Boolean = false) 
// Override toString to display the task in "human"
override fun toString(): String
var done = ""
if (isDone)
done = "X"

return "$name t$done"

// function to transform the task in a line to be written in the file
fun toLine(): String
return "$name$SEPARATOR$isDone"




In order to transform a line from my task file into a Task instance, it's quite straightforward:



fun parse(line: String): Task 
val array = line.split(SEPARATOR)
if (array.size < 2)
return Task("", false)

return Task(sanitize(array[0]), sanitize(array[1]).toBoolean())


fun sanitize(s: String): String
return s.replace("n", "")



I created an interface Cmd which represents a command:



interface Cmd 
fun getOption(): Option
fun isEnabled(line: CommandLine): Boolean
fun getOptionValue(line: CommandLine): String?



I also created a ActionCmd which represents an action command, like adding, finishing, or listing the tasks. This ActionCmd implements the Cmd interface:



interface ActionCmd: Cmd 
fun execute(p: Path, arg: String)



In order to avoid duplicating the code for all my commands, I created an abstract class AbstractCmd that uses the commons-CLI classes:



abstract class AbstractCmd: Cmd 
override fun isEnabled(line: CommandLine): Boolean
return line.hasOption(getOption().longOpt)


override fun getOptionValue(line: CommandLine): String?
return line.getOptionValue(getOption().longOpt)




Finally, the action commands are the following:



class ListCmd : AbstractCmd(), ActionCmd 
private val option = Option("l", "list", false, "print the list of tasks")
override fun getOption(): Option
return option


override fun execute(p: Path, arg: String)
val tasks = ArrayList<Task>()
val stream = Files.newBufferedReader(p)
stream.buffered().lines().forEach line -> tasks.add(parse(line))
tasks.forEach println(it)



class AddCmd: AbstractCmd(), ActionCmd
private val option = Option("a", "add", true, "add a task")
override fun getOption(): Option
return option


override fun execute(p: Path, arg: String)
// I have to add the empty string, otherwise, it's not going to add a new line
p.toFile().appendText("" + Task(arg).toLine())



class FinishCmd : AbstractCmd(), ActionCmd
private val option = Option("f", "finish", true, "finish a task")
override fun getOption(): Option
return option


override fun execute(p: Path, arg: String)
val task = Task(arg)

val tasks = ArrayList<Task>()
val readerStream = Files.newBufferedReader(p)
readerStream.buffered().lines().forEach line ->
val t = parse(line)
if (t.name == task.name)
t.isDone = true
debug("Finishing task: $t")

tasks.add(t)

File(p.toString()).printWriter().use out ->
tasks.forEach out.println(it.toLine())





Does my code follow common best practices or am I going the wrong way?







share|improve this question



























    up vote
    6
    down vote

    favorite












    I'm learning Kotlin and I made a todo program (in command line) with Kotlin and Maven as my build tool.



    Full project.



    Description



    The idea of my program is to read a file (path defined in a config file) that contains the list of tasks.



    Since it's a project for practice purpose, the content of the file is quite simple and looks like this:



    foo;true
    bar;false
    foobar;true


    2 columns:



    • Description of the task

    • Status of the task

    The only actions I've created are the following:




    • list the tasks (on the standard output)


    • add a new task (by writing a new line on the file)


    • finish a task (by setting the status of the task to true)

    There are also other options:




    • help: display the list of options in the standard output


    • config: use another configuration file


    • verbose: display the debug logs


    • version: display the version of the program

    The code



    I'm using commons CLI library to help me parse command line options passed in the arguments.



    I represented a task with the following:



    class Task(var name: String, var isDone: Boolean = false) 
    // Override toString to display the task in "human"
    override fun toString(): String
    var done = ""
    if (isDone)
    done = "X"

    return "$name t$done"

    // function to transform the task in a line to be written in the file
    fun toLine(): String
    return "$name$SEPARATOR$isDone"




    In order to transform a line from my task file into a Task instance, it's quite straightforward:



    fun parse(line: String): Task 
    val array = line.split(SEPARATOR)
    if (array.size < 2)
    return Task("", false)

    return Task(sanitize(array[0]), sanitize(array[1]).toBoolean())


    fun sanitize(s: String): String
    return s.replace("n", "")



    I created an interface Cmd which represents a command:



    interface Cmd 
    fun getOption(): Option
    fun isEnabled(line: CommandLine): Boolean
    fun getOptionValue(line: CommandLine): String?



    I also created a ActionCmd which represents an action command, like adding, finishing, or listing the tasks. This ActionCmd implements the Cmd interface:



    interface ActionCmd: Cmd 
    fun execute(p: Path, arg: String)



    In order to avoid duplicating the code for all my commands, I created an abstract class AbstractCmd that uses the commons-CLI classes:



    abstract class AbstractCmd: Cmd 
    override fun isEnabled(line: CommandLine): Boolean
    return line.hasOption(getOption().longOpt)


    override fun getOptionValue(line: CommandLine): String?
    return line.getOptionValue(getOption().longOpt)




    Finally, the action commands are the following:



    class ListCmd : AbstractCmd(), ActionCmd 
    private val option = Option("l", "list", false, "print the list of tasks")
    override fun getOption(): Option
    return option


    override fun execute(p: Path, arg: String)
    val tasks = ArrayList<Task>()
    val stream = Files.newBufferedReader(p)
    stream.buffered().lines().forEach line -> tasks.add(parse(line))
    tasks.forEach println(it)



    class AddCmd: AbstractCmd(), ActionCmd
    private val option = Option("a", "add", true, "add a task")
    override fun getOption(): Option
    return option


    override fun execute(p: Path, arg: String)
    // I have to add the empty string, otherwise, it's not going to add a new line
    p.toFile().appendText("" + Task(arg).toLine())



    class FinishCmd : AbstractCmd(), ActionCmd
    private val option = Option("f", "finish", true, "finish a task")
    override fun getOption(): Option
    return option


    override fun execute(p: Path, arg: String)
    val task = Task(arg)

    val tasks = ArrayList<Task>()
    val readerStream = Files.newBufferedReader(p)
    readerStream.buffered().lines().forEach line ->
    val t = parse(line)
    if (t.name == task.name)
    t.isDone = true
    debug("Finishing task: $t")

    tasks.add(t)

    File(p.toString()).printWriter().use out ->
    tasks.forEach out.println(it.toLine())





    Does my code follow common best practices or am I going the wrong way?







    share|improve this question























      up vote
      6
      down vote

      favorite









      up vote
      6
      down vote

      favorite











      I'm learning Kotlin and I made a todo program (in command line) with Kotlin and Maven as my build tool.



      Full project.



      Description



      The idea of my program is to read a file (path defined in a config file) that contains the list of tasks.



      Since it's a project for practice purpose, the content of the file is quite simple and looks like this:



      foo;true
      bar;false
      foobar;true


      2 columns:



      • Description of the task

      • Status of the task

      The only actions I've created are the following:




      • list the tasks (on the standard output)


      • add a new task (by writing a new line on the file)


      • finish a task (by setting the status of the task to true)

      There are also other options:




      • help: display the list of options in the standard output


      • config: use another configuration file


      • verbose: display the debug logs


      • version: display the version of the program

      The code



      I'm using commons CLI library to help me parse command line options passed in the arguments.



      I represented a task with the following:



      class Task(var name: String, var isDone: Boolean = false) 
      // Override toString to display the task in "human"
      override fun toString(): String
      var done = ""
      if (isDone)
      done = "X"

      return "$name t$done"

      // function to transform the task in a line to be written in the file
      fun toLine(): String
      return "$name$SEPARATOR$isDone"




      In order to transform a line from my task file into a Task instance, it's quite straightforward:



      fun parse(line: String): Task 
      val array = line.split(SEPARATOR)
      if (array.size < 2)
      return Task("", false)

      return Task(sanitize(array[0]), sanitize(array[1]).toBoolean())


      fun sanitize(s: String): String
      return s.replace("n", "")



      I created an interface Cmd which represents a command:



      interface Cmd 
      fun getOption(): Option
      fun isEnabled(line: CommandLine): Boolean
      fun getOptionValue(line: CommandLine): String?



      I also created a ActionCmd which represents an action command, like adding, finishing, or listing the tasks. This ActionCmd implements the Cmd interface:



      interface ActionCmd: Cmd 
      fun execute(p: Path, arg: String)



      In order to avoid duplicating the code for all my commands, I created an abstract class AbstractCmd that uses the commons-CLI classes:



      abstract class AbstractCmd: Cmd 
      override fun isEnabled(line: CommandLine): Boolean
      return line.hasOption(getOption().longOpt)


      override fun getOptionValue(line: CommandLine): String?
      return line.getOptionValue(getOption().longOpt)




      Finally, the action commands are the following:



      class ListCmd : AbstractCmd(), ActionCmd 
      private val option = Option("l", "list", false, "print the list of tasks")
      override fun getOption(): Option
      return option


      override fun execute(p: Path, arg: String)
      val tasks = ArrayList<Task>()
      val stream = Files.newBufferedReader(p)
      stream.buffered().lines().forEach line -> tasks.add(parse(line))
      tasks.forEach println(it)



      class AddCmd: AbstractCmd(), ActionCmd
      private val option = Option("a", "add", true, "add a task")
      override fun getOption(): Option
      return option


      override fun execute(p: Path, arg: String)
      // I have to add the empty string, otherwise, it's not going to add a new line
      p.toFile().appendText("" + Task(arg).toLine())



      class FinishCmd : AbstractCmd(), ActionCmd
      private val option = Option("f", "finish", true, "finish a task")
      override fun getOption(): Option
      return option


      override fun execute(p: Path, arg: String)
      val task = Task(arg)

      val tasks = ArrayList<Task>()
      val readerStream = Files.newBufferedReader(p)
      readerStream.buffered().lines().forEach line ->
      val t = parse(line)
      if (t.name == task.name)
      t.isDone = true
      debug("Finishing task: $t")

      tasks.add(t)

      File(p.toString()).printWriter().use out ->
      tasks.forEach out.println(it.toLine())





      Does my code follow common best practices or am I going the wrong way?







      share|improve this question













      I'm learning Kotlin and I made a todo program (in command line) with Kotlin and Maven as my build tool.



      Full project.



      Description



      The idea of my program is to read a file (path defined in a config file) that contains the list of tasks.



      Since it's a project for practice purpose, the content of the file is quite simple and looks like this:



      foo;true
      bar;false
      foobar;true


      2 columns:



      • Description of the task

      • Status of the task

      The only actions I've created are the following:




      • list the tasks (on the standard output)


      • add a new task (by writing a new line on the file)


      • finish a task (by setting the status of the task to true)

      There are also other options:




      • help: display the list of options in the standard output


      • config: use another configuration file


      • verbose: display the debug logs


      • version: display the version of the program

      The code



      I'm using commons CLI library to help me parse command line options passed in the arguments.



      I represented a task with the following:



      class Task(var name: String, var isDone: Boolean = false) 
      // Override toString to display the task in "human"
      override fun toString(): String
      var done = ""
      if (isDone)
      done = "X"

      return "$name t$done"

      // function to transform the task in a line to be written in the file
      fun toLine(): String
      return "$name$SEPARATOR$isDone"




      In order to transform a line from my task file into a Task instance, it's quite straightforward:



      fun parse(line: String): Task 
      val array = line.split(SEPARATOR)
      if (array.size < 2)
      return Task("", false)

      return Task(sanitize(array[0]), sanitize(array[1]).toBoolean())


      fun sanitize(s: String): String
      return s.replace("n", "")



      I created an interface Cmd which represents a command:



      interface Cmd 
      fun getOption(): Option
      fun isEnabled(line: CommandLine): Boolean
      fun getOptionValue(line: CommandLine): String?



      I also created a ActionCmd which represents an action command, like adding, finishing, or listing the tasks. This ActionCmd implements the Cmd interface:



      interface ActionCmd: Cmd 
      fun execute(p: Path, arg: String)



      In order to avoid duplicating the code for all my commands, I created an abstract class AbstractCmd that uses the commons-CLI classes:



      abstract class AbstractCmd: Cmd 
      override fun isEnabled(line: CommandLine): Boolean
      return line.hasOption(getOption().longOpt)


      override fun getOptionValue(line: CommandLine): String?
      return line.getOptionValue(getOption().longOpt)




      Finally, the action commands are the following:



      class ListCmd : AbstractCmd(), ActionCmd 
      private val option = Option("l", "list", false, "print the list of tasks")
      override fun getOption(): Option
      return option


      override fun execute(p: Path, arg: String)
      val tasks = ArrayList<Task>()
      val stream = Files.newBufferedReader(p)
      stream.buffered().lines().forEach line -> tasks.add(parse(line))
      tasks.forEach println(it)



      class AddCmd: AbstractCmd(), ActionCmd
      private val option = Option("a", "add", true, "add a task")
      override fun getOption(): Option
      return option


      override fun execute(p: Path, arg: String)
      // I have to add the empty string, otherwise, it's not going to add a new line
      p.toFile().appendText("" + Task(arg).toLine())



      class FinishCmd : AbstractCmd(), ActionCmd
      private val option = Option("f", "finish", true, "finish a task")
      override fun getOption(): Option
      return option


      override fun execute(p: Path, arg: String)
      val task = Task(arg)

      val tasks = ArrayList<Task>()
      val readerStream = Files.newBufferedReader(p)
      readerStream.buffered().lines().forEach line ->
      val t = parse(line)
      if (t.name == task.name)
      t.isDone = true
      debug("Finishing task: $t")

      tasks.add(t)

      File(p.toString()).printWriter().use out ->
      tasks.forEach out.println(it.toLine())





      Does my code follow common best practices or am I going the wrong way?









      share|improve this question












      share|improve this question




      share|improve this question








      edited Apr 29 at 15:54









      Billal BEGUERADJ

      1




      1









      asked Feb 25 at 17:41









      l-lin

      1312




      1312




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          4
          down vote













          Here are some recommendations:



          Use if as expression when it's appropriate.



          var done = ""
          if (isDone)
          done = "X"



          The better way is to write:



          val done = if (isDone) "X" else ""


          Also try to use val as much as it's possible. That will make your code simpler and more reliable.



          Don't write obvious comments like comments for toString or toLine functions.



          I would rename functions toLine and parse to serialize/deserialize. Or I'd use just toString + parse.



          Using global variables like SEPARATOR is a bad idea.



          I'd recommend use data class for Task and Commands.



          private val option = Option("a", "add", true, "add a task")
          override fun getOption(): Option
          return option



          It equals to



          val option = Option("a", "add", true, "add a task")


          Also it's a good practice to avoid using in functions many arguments with the same type. If you can't avoid you still can name them explicitly by writing method(param = arg1..)



          This looks weird



          p.toFile().appendText("" + Task(arg).toLine())


          Try to use more filters, maps, and other hi-order functions over collections



          val tasks = ArrayList<Task>()
          val stream = Files.newBufferedReader(p)
          stream.buffered().lines().forEach line -> tasks.add(parse(line))
          tasks.forEach println(it)


          This is just:



          p.toFile().readLines().map parse(it) .forEach 
          println(it)



          Another example:



           val tasks = ArrayList<Task>()
          val readerStream = Files.newBufferedReader(p)
          readerStream.buffered().lines().forEach line ->
          val t = parse(line)
          if (t.name == task.name)
          t.isDone = true
          debug("Finishing task: $t")

          tasks.add(t)



          Is just



          val tasks = p!!.toFile().readLines().map parse(it) 
          commands.filter it.name == task.name .forEach it.isDone = true


          If you want I can rewrite your program on my taste (as example).






          share|improve this answer























          • "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
            – l-lin
            Mar 25 at 16:14











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188330%2ftodo-app-in-kotlin%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          4
          down vote













          Here are some recommendations:



          Use if as expression when it's appropriate.



          var done = ""
          if (isDone)
          done = "X"



          The better way is to write:



          val done = if (isDone) "X" else ""


          Also try to use val as much as it's possible. That will make your code simpler and more reliable.



          Don't write obvious comments like comments for toString or toLine functions.



          I would rename functions toLine and parse to serialize/deserialize. Or I'd use just toString + parse.



          Using global variables like SEPARATOR is a bad idea.



          I'd recommend use data class for Task and Commands.



          private val option = Option("a", "add", true, "add a task")
          override fun getOption(): Option
          return option



          It equals to



          val option = Option("a", "add", true, "add a task")


          Also it's a good practice to avoid using in functions many arguments with the same type. If you can't avoid you still can name them explicitly by writing method(param = arg1..)



          This looks weird



          p.toFile().appendText("" + Task(arg).toLine())


          Try to use more filters, maps, and other hi-order functions over collections



          val tasks = ArrayList<Task>()
          val stream = Files.newBufferedReader(p)
          stream.buffered().lines().forEach line -> tasks.add(parse(line))
          tasks.forEach println(it)


          This is just:



          p.toFile().readLines().map parse(it) .forEach 
          println(it)



          Another example:



           val tasks = ArrayList<Task>()
          val readerStream = Files.newBufferedReader(p)
          readerStream.buffered().lines().forEach line ->
          val t = parse(line)
          if (t.name == task.name)
          t.isDone = true
          debug("Finishing task: $t")

          tasks.add(t)



          Is just



          val tasks = p!!.toFile().readLines().map parse(it) 
          commands.filter it.name == task.name .forEach it.isDone = true


          If you want I can rewrite your program on my taste (as example).






          share|improve this answer























          • "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
            – l-lin
            Mar 25 at 16:14















          up vote
          4
          down vote













          Here are some recommendations:



          Use if as expression when it's appropriate.



          var done = ""
          if (isDone)
          done = "X"



          The better way is to write:



          val done = if (isDone) "X" else ""


          Also try to use val as much as it's possible. That will make your code simpler and more reliable.



          Don't write obvious comments like comments for toString or toLine functions.



          I would rename functions toLine and parse to serialize/deserialize. Or I'd use just toString + parse.



          Using global variables like SEPARATOR is a bad idea.



          I'd recommend use data class for Task and Commands.



          private val option = Option("a", "add", true, "add a task")
          override fun getOption(): Option
          return option



          It equals to



          val option = Option("a", "add", true, "add a task")


          Also it's a good practice to avoid using in functions many arguments with the same type. If you can't avoid you still can name them explicitly by writing method(param = arg1..)



          This looks weird



          p.toFile().appendText("" + Task(arg).toLine())


          Try to use more filters, maps, and other hi-order functions over collections



          val tasks = ArrayList<Task>()
          val stream = Files.newBufferedReader(p)
          stream.buffered().lines().forEach line -> tasks.add(parse(line))
          tasks.forEach println(it)


          This is just:



          p.toFile().readLines().map parse(it) .forEach 
          println(it)



          Another example:



           val tasks = ArrayList<Task>()
          val readerStream = Files.newBufferedReader(p)
          readerStream.buffered().lines().forEach line ->
          val t = parse(line)
          if (t.name == task.name)
          t.isDone = true
          debug("Finishing task: $t")

          tasks.add(t)



          Is just



          val tasks = p!!.toFile().readLines().map parse(it) 
          commands.filter it.name == task.name .forEach it.isDone = true


          If you want I can rewrite your program on my taste (as example).






          share|improve this answer























          • "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
            – l-lin
            Mar 25 at 16:14













          up vote
          4
          down vote










          up vote
          4
          down vote









          Here are some recommendations:



          Use if as expression when it's appropriate.



          var done = ""
          if (isDone)
          done = "X"



          The better way is to write:



          val done = if (isDone) "X" else ""


          Also try to use val as much as it's possible. That will make your code simpler and more reliable.



          Don't write obvious comments like comments for toString or toLine functions.



          I would rename functions toLine and parse to serialize/deserialize. Or I'd use just toString + parse.



          Using global variables like SEPARATOR is a bad idea.



          I'd recommend use data class for Task and Commands.



          private val option = Option("a", "add", true, "add a task")
          override fun getOption(): Option
          return option



          It equals to



          val option = Option("a", "add", true, "add a task")


          Also it's a good practice to avoid using in functions many arguments with the same type. If you can't avoid you still can name them explicitly by writing method(param = arg1..)



          This looks weird



          p.toFile().appendText("" + Task(arg).toLine())


          Try to use more filters, maps, and other hi-order functions over collections



          val tasks = ArrayList<Task>()
          val stream = Files.newBufferedReader(p)
          stream.buffered().lines().forEach line -> tasks.add(parse(line))
          tasks.forEach println(it)


          This is just:



          p.toFile().readLines().map parse(it) .forEach 
          println(it)



          Another example:



           val tasks = ArrayList<Task>()
          val readerStream = Files.newBufferedReader(p)
          readerStream.buffered().lines().forEach line ->
          val t = parse(line)
          if (t.name == task.name)
          t.isDone = true
          debug("Finishing task: $t")

          tasks.add(t)



          Is just



          val tasks = p!!.toFile().readLines().map parse(it) 
          commands.filter it.name == task.name .forEach it.isDone = true


          If you want I can rewrite your program on my taste (as example).






          share|improve this answer















          Here are some recommendations:



          Use if as expression when it's appropriate.



          var done = ""
          if (isDone)
          done = "X"



          The better way is to write:



          val done = if (isDone) "X" else ""


          Also try to use val as much as it's possible. That will make your code simpler and more reliable.



          Don't write obvious comments like comments for toString or toLine functions.



          I would rename functions toLine and parse to serialize/deserialize. Or I'd use just toString + parse.



          Using global variables like SEPARATOR is a bad idea.



          I'd recommend use data class for Task and Commands.



          private val option = Option("a", "add", true, "add a task")
          override fun getOption(): Option
          return option



          It equals to



          val option = Option("a", "add", true, "add a task")


          Also it's a good practice to avoid using in functions many arguments with the same type. If you can't avoid you still can name them explicitly by writing method(param = arg1..)



          This looks weird



          p.toFile().appendText("" + Task(arg).toLine())


          Try to use more filters, maps, and other hi-order functions over collections



          val tasks = ArrayList<Task>()
          val stream = Files.newBufferedReader(p)
          stream.buffered().lines().forEach line -> tasks.add(parse(line))
          tasks.forEach println(it)


          This is just:



          p.toFile().readLines().map parse(it) .forEach 
          println(it)



          Another example:



           val tasks = ArrayList<Task>()
          val readerStream = Files.newBufferedReader(p)
          readerStream.buffered().lines().forEach line ->
          val t = parse(line)
          if (t.name == task.name)
          t.isDone = true
          debug("Finishing task: $t")

          tasks.add(t)



          Is just



          val tasks = p!!.toFile().readLines().map parse(it) 
          commands.filter it.name == task.name .forEach it.isDone = true


          If you want I can rewrite your program on my taste (as example).







          share|improve this answer















          share|improve this answer



          share|improve this answer








          edited Apr 29 at 9:45









          Zoe

          20519




          20519











          answered Mar 21 at 19:12









          llama

          1013




          1013











          • "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
            – l-lin
            Mar 25 at 16:14

















          • "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
            – l-lin
            Mar 25 at 16:14
















          "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
          – l-lin
          Mar 25 at 16:14





          "Using global variables like SEPARATOR is a bad idea." I wanted to use a constant, not a global variable. What should be done instead? val option = Option("a", "add", true, "add a task") The getOption method was declared in the interface as I needed to abstract the implentation when fetching all the options.
          – l-lin
          Mar 25 at 16:14













           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188330%2ftodo-app-in-kotlin%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Greedy Best First Search implementation in Rust

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          C++11 CLH Lock Implementation