How I use ChatGPT when writing code.

ChatGPT 3.5 and AI in general is not yet a programmer, even if some are expecting it to become one. I have tried it several times myself, and my conclusion is the same as many other professional programmers: it is not yet ready to replace a human programmer. 

You must have domain competence to be able to correct the erroneous answers received from chatGPT. It is the same if you ask chatGPT to write some code. But if used as the Devil’s Advocate, it might help you improve the robustness and maintainability of the code as described in this article. 

I’ve observed some use of it as an advanced search tool, and I’ve used it when I’ve forgotten how to write an if-statement in an obscure language such as JavaScript. However, in this article I will show how I used it to find two errors in my Python code. Note that this is not the full conversation I had with chatGPT and it is only a subset of my implementation – hopefully just enough to show a possible interesting use of chatGPT already, as an aid in finding test cases.

This was the specification I was going to implement
Write a function adapt_recipe(txt, x), which reads a text for a food recipe and adapts it to x times its size, where x can be an integer or a float (e.g. 3 or 0.5). A recipe consists of lines, where each line has an optional number, a unit, and an ingredient. The adaptation multiplies the number by x, resulting in a different line. If there is no number, no change is performed. The number is rounded to one decimal.

 

This is my implementation in Python

def adapt_recipe(txt, x):
   adapted_recipte = ""
   for line in txt.splitlines():
         number = line.split(" ")[0]
         if number.isdecimal() :
               volume = round(float(number)*float(x),1)
               adapted_recipte = adapted_recipte + str(volume) + " " + line.replace(number,"") + "\n"
        else:
              adapted_recipte = adapted_recipte + line
   return adapted_recipte
First I asked ChatGPT to suggest some improvements to this code and provided the specification  above and my implementation and got this answer

 

ChatGPT answer start
Your implementation looks like a good start, but there are a few areas where you can make improvements and handle edge cases more effectively. Here’s an improved version of your code:

def adapt_recipe(txt, x):
   adapted_recipe = ""
   for line in txt.splitlines():
      parts = line.split(None, 1) # Split the line into number and the rest of the line
      if len(parts) == 2:
         number, rest_of_line = parts
         try:
           number = float(number)
           volume = round(number * x, 1)
           adapted_recipe += f"{volume} {rest_of_line}\n"
         except ValueError:
           # Handle cases where the number cannot be converted to a float
           adapted_recipe += line + "\n"
      else:
         # If the line doesn't contain a number, just append it as is
         adapted_recipe += line + "\n"
   return adapted_recipe

Improvements and explanations:

  1. I split each line into two parts: the number and the rest of the line using “split(None, 1)” to better handle variations in formatting.
  2. I added error handling with a “try-except block” to catch cases where the number can’t be converted to a float. This ensures that lines without valid numbers won’t cause the function to fail.
  3. The code now handles lines without numbers by directly appending them without modification.
  4. I used an f-string to make the string concatenation more concise and readable.
ChatGPT answer end

 

From the above suggestion I found that my original code was missing a “\n

 

Secondly I asked ” Please, suggest some test cases “

 

ChatGPT answer start
Here’s some suggested test cases
# Test cases
test_recipe = """
   1 cup flour
   2.5 tbsp sugar
   Salt to taste
   Eggs - 2
"""

# Test case 1: Adapt the recipe to 3 times its size (integer)
result = adapt_recipe(test_recipe, 3)
print(result)

# Test case 2: Adapt the recipe to half its size (float)
result = adapt_recipe(test_recipe, 0.5)
print(result)

# Test case 3: No scaling, the recipe remains the same
result = adapt_recipe(test_recipe, 1)
print(result)
ChatGPT answer end

 

I had several more “discussions” with ChatGPT, which included some more test cases, but nothing that made me update my implementation.

The second example gave more help than the above one. This was the requirements

Ingredients in food recipes can be represented by a class Ingredient, which collects together information about them: the name, the unit used, and the amount of calories per unit. Define this class so that the frittata recipe can be defined as a list of tuples of amounts and Ingredient objects, as in the screen dump to the right above. Notice that the missing amount is represented as None. Also define a function calories(ingrs), which computes the total amount of calories in a recipe and works in the way shown to the right below. If the amount is None, that ingredient is just ignored.

And this was the code I gave ChatGPT as my implementation

def calories(ingre):
    total_calories = 0
    for ingredient in ingre:
        if str(ingredient[0]).isdecimal():
            total_calories = total_calories + ingredient[1].amount_of_calories * ingredient[0]
    print ("Total calories: ", total_calories)
class Ingredient:
    def __init__(self, name, unit, amount_of_calories):
        self.name = name
        self.unit = unit
        self.amount_of_calories = amount_of_calories
My question to ChatGPT was this: Please, suggest improvements and test cases for my implementation to this requirement:

 

ChatGPT answer start
class Ingredient:

def __init__(self, name, unit, amount_of_calories):
   self.name = name
   self.unit = unit
   self.amount_of_calories = amount_of_calories

def calories(ingre):
   total_calories = 0
   for ingredient in ingre:
      if ingredient[0] is not None and str(ingredient[0]).isdecimal():
         total_calories += ingredient[1].amount_of_calories * ingredient[0]
   return total_calories

# Test cases
if __name__ == "__main__":
   # Create Ingredient objects
   egg = Ingredient("Egg", "unit", 68)
   cheese = Ingredient("Cheese", "gram", 110)
   bacon = Ingredient("Bacon", "strip", 42)

   # Define a frittata recipe
   frittata_recipe = [
      (2, egg),
      (None, cheese), # Test None as the amount
      (3, bacon),
   ]

   # Calculate calories in the frittata recipe
   total_calories = calories(frittata_recipe)

   print("Total calories in the frittata recipe:", total_calories) # Expected output: 2 * 68 + 3 * 42 = 282

 

Improvements and suggestions:

  1. In the “calories” function, I’ve added a check for “ingredient[0] is not None” to ignore ingredients with “None” as their amount.
  2. I’ve removed the “print” statement from the “calories” function since it’s generally better to return the value and let the caller decide whether to print or use the result.
  3. I’ve added test cases to demonstrate how the code works, including a case where one ingredient has “None” as the amount.
  4. Ensure that the “amount_of_calories” is a numeric value (integer or float) when creating Ingredient objects. It’s a good practice to validate inputs to your class.
  5. Make sure to define the ingredients and the frittata recipe as needed for your application.
ChatGPT answer end

 

Then an interesting discussion took place about the sum as you see above it is not correctly calculated:
All the apologize are getting a little bit irritating since it only takes time to read. I would appreciate some more specific, precise and direct language.
And then I got some more test cases after asking again:

 

ChatGPT answer start
# Test Case 1: Empty recipe
empty_recipe = []
assert calories(empty_recipe) == 0

# Test Case 2: Recipe with a single ingredient
single_ingredient_recipe = [(2, Ingredient('carrot', 'g', 41))]
assert calories(single_ingredient_recipe) == 2 * 41

# Test Case 3: Recipe with multiple ingredients and one ingredient having None as amount
mixed_recipe = [
   (3, Ingredient('chicken breast', 'oz', 46)),
   (None, Ingredient('sugar', 'g', 387)), # Ignored due to None
   (2, Ingredient('broccoli', 'g', 34)),
   (1.5, Ingredient('milk', 'cup', 103)),
]
assert calories(mixed_recipe) == 3 * 46 + 2 * 34 + 1.5 * 103

# Test Case 4: Recipe with all ingredients having None as amount (should result in 0 calories)
no_amount_recipe = [
   (None, Ingredient('flour', 'g', 364)),
   (None, Ingredient('sugar', 'g', 387)),
   (None, Ingredient('butter', 'g', 717)),
]
assert calories(no_amount_recipe) == 0

# Test Case 5: Recipe with negative amounts (should be treated as 0 calories)
negative_amount_recipe = [
   (-1, Ingredient('apple', 'unit', 52)),
   (2, Ingredient('banana', 'unit', 105)),
]
assert calories(negative_amount_recipe) == 2 * 105 # The negative amount is ignored

# Test Case 6: Recipe with ingredients having zero calories
zero_calories_recipe = [
   (2, Ingredient('lettuce', 'g', 0)),
   (3, Ingredient('tomato', 'unit', 0)),
   (1, Ingredient('cucumber', 'g', 0)),
]
assert calories(zero_calories_recipe) == 0

print("All test cases passed!")

 

These test cases cover various scenarios, including empty recipes, different units, ignored ingredients with “None” amounts, negative amounts, and ingredients with zero calories. Each assertion checks whether the calculated total calories match the expected result. If all assertions pass, it will print “All test cases passed!” to indicate success.

ChatGPT answer end

 

When running the test cases i found that
str(ingredient[0]).isdecimal()
returned false when the value is 1.5 and asked chatGPT to help. As usual it started to apologize and then gave me the following update:

 

ChatGPT answer start
You are correct, and I apologize for the oversight. The “str(ingredient[0]).isdecimal()” condition will return “False” for floating-point numbers like 1.5 because “isdecimal()” checks if the entire string consists of decimal characters (0-9), but it doesn’t account for decimal points.To correctly handle floating-point numbers, you can use a more robust approach using the “isnumeric()” method. Here’s the revised “calories” function:

def calories(ingre):
   total_calories = 0
   for amount, ingredient in ingre:
      if amount is not None and str(amount).replace(".", "", 1).isnumeric():
         total_calories += ingredient.amount_of_calories * amount
   return total_calories
In this updated code, the replace(".", "", 1) part is used to remove the decimal point in case of floating-point numbers before checking if the string is numeric. This change ensures that the condition works correctly for both integers and floating-point numbers.
ChatGPT answer end

 

These test cases and information from chatGPT made me changed the code to the below with changes in bold. It is an improvement but it still will fail if the input is wrong like “12..55”

def calories(ingre):
    total_calories = 0
    for ingredient in ingre:
        if str(ingredient[0]).replace(".", "", 1).isdecimal():
            total_calories = total_calories + ingredient[1].amount_of_calories * float(ingredient[0])
        else:
            print(ingredient[0], ingredient[1].amount_of_calories )
    return (total_calories)

Even if I found two errors in my code, it took many hours to investigate the information that chatGPT presented. You can never trust anything that chatGPT writes, as chatGPT states itself at the bottom of the tool: “chatGPT can make mistakes. Consider checking important information.” If one has a colleague that has time to review the code, it is still probably the most efficient “tool” to use.