Last week, Open AI released this new ChatGPT assistant, and it has taken the world by storm.
But what is ChatGPT, and how does it work?
According to the official announcement:
We’ve trained a model called ChatGPT which interacts in a conversational way. The dialogue format makes it possible for ChatGPT to answer followup questions, admit its mistakes, challenge incorrect premises, and reject inappropriate requests.
ChatGPT is optimized for dialogue, and this makes it somewhat different from GitHub Copilot.
To find out how good it is with Dart & Flutter, I decided to take it for a ride and test it with various coding tasks.
So in this article, I'll share some of my experiments with ChatGPT, show you how well it did, and try to give objective answers to the most pressing questions in life:
- Can you trust ChatGPT to produce correct code for you? 😉
- How to make the most of it? 🛠
- Will AI take your job away? 😱
Ready? Let's dive in!
Using ChatGPT with Dart & Flutter: Methodology
To get started, I decided to test ChatGPT on various kinds of tasks:
- Detect and correct common coding errors
- Explain how code works
- Write or complete code to solve a given task
For code writing tasks, I followed a two-step process:
- ask to write code to solve a specific, discrete problem
- verify if the code compiles, runs, and produces the correct output
When the output was not as expected, I asked follow-up questions to see if ChatGPT would correct itself.
I repeated this process with nine different tasks. You can find all the results below, along with my observations. 👇
Note that this is a long article. If you're short on time and want to cut to the chase, feel free to jump to the final results and evaluation.
For improved readability, I have included my dialogues with ChatGPT without modifications (rather than pasting screenshots). You can ask the very same questions on the ChatGPT page if you wish - though note that the output can vary, and ChatGPT will produce slightly different responses every time. To learn about how the model was trained, read here and here.
Experiment 1: Detect and Fix an Error
Me: Is there something wrong with this code?
Future<String> doSomeAsyncWork(String debugName) async {
Future.delayed(Duration(seconds: 1));
return debugName;
}
AI: Yes, there is a problem with this code. The Future.delayed
method returns a Future
, but in this code, the returned Future
is not being await
ed or assigned to a variable. This means that the code will not actually pause for one second before returning the debugName
parameter.
Here is one way to fix the code:
Future<String> doSomeAsyncWork(String debugName) async {
await Future.delayed(Duration(seconds: 1));
return debugName;
}
Alternatively, you can use the then
method to chain a function that will be called once the Future
returned by Future.delayed
completes:
Future<String> doSomeAsyncWork(String debugName) {
return Future.delayed(Duration(seconds: 1)).then((_) => debugName);
}
In both of these examples, the code will pause for one second before returning the debugName
parameter.
My comments
Forgetting to use await
is a common mistake and not something the static analyzer will point out (since it's not a syntax error).
But with ChatGPT, it didn't go unnoticed.
What's more, it pointed out an alternative implementation based on .then
. I didn't think about that! 🤯
This shows that ChatGPT can reduce the time spent on debugging. 👍
Final result: success! ✅
If we want, we can explicitly enable the
unawaited_futures
linter rule (which is disabled by default) to get a warning if we forget to await aFuture
inside an async function body. To learn more about custom lint rules, read: Flutter Linting and Linter Comparison.
Experiment 2: Explain how some code works
Me: Can you explain how this code works?
import 'package:freezed_annotation/freezed_annotation.dart';
import 'tmdb_movie.dart';
part 'tmdb_movies_response.freezed.dart';
part 'tmdb_movies_response.g.dart';
@freezed
class TMDBMoviesResponse with _$TMDBMoviesResponse {
factory TMDBMoviesResponse({
required int page,
required List<TMDBMovie> results,
@JsonKey(name: 'total_results') required int totalResults,
@JsonKey(name: 'total_pages') required int totalPages,
@Default([]) List<String> errors,
}) = _TMDBMoviesResponse;
factory TMDBMoviesResponse.fromJson(Map<String, dynamic> json) =>
_$TMDBMoviesResponseFromJson(json);
}
AI This code defines a TMDBMoviesResponse
class in the Dart programming language. The class is marked with the @freezed
annotation, which is a Dart package called freezed_annotation
that provides a way to create "immutable and serializable classes" in Dart.
The TMDBMoviesResponse
class has several fields that represent data that might be returned from some kind of API, such as page
, results
, totalResults
, and totalPages
. These fields are marked as required, which means that they must be provided when creating an instance of the class.
The TMDBMoviesResponse
class also has a errors
field, which is marked with the @Default
annotation and is initialized to an empty List<String>
(an empty list of strings). This means that if no value is provided for the errors
field when creating an instance of the class, it will be initialized to an empty list.
The class also has a factory
constructor called TMDBMoviesResponse.fromJson
, which takes in a Map<String, dynamic>
(a map of keys and values where the values can be of any type) and uses it to create and initialize an instance of the TMDBMoviesResponse
class. This constructor is used to create an instance of the class from a JSON object, which is commonly used as a way to represent data in APIs.
It's worth noting that the code includes two part
directives: 'tmdb_movies_response.freezed.dart'
and 'tmdb_movies_response.g.dart'
. The part
directive is a way to include code from another file in the same Dart library or package. In this case, it's likely that the tmdb_movies_response.freezed.dart
file contains additional code that is related to the freezed
package, while the tmdb_movies_response.g.dart
file contains generated code that is used to create instances of the TMDBMoviesResponse
class from a JSON object.
My comments
ChatGPT clearly knows about the Freezed package and how it works. ❄️
People who never used Dart code generation would struggle to understand the syntax above and will highly appreciate such a detailed explanation. 🙏
Final result: success! ✅
Experiment 3: Complete a binary search implementation
Me: I'm writing a binary search function to find an item in an ordered list of integers. Can you add the missing code and briefly explain how it works?
int binarySearch(List<int> list, int item) {
int low = 0;
int high = list.length - 1;
// TODO: implement
// If the item is not found, return -1
return -1;
}
AI: Sure, here's one way to implement a binary search function in Dart:
int binarySearch(List<int> list, int item) {
int low = 0;
int high = list.length - 1;
while (low <= high) {
// Calculate the middle index
int mid = (low + high) ~/ 2;
// Get the item at the middle index
int guess = list[mid];
if (guess == item) {
// If the guess is correct, return the index
return mid;
} else if (guess > item) {
// If the guess is too high, reduce the high index
high = mid - 1;
} else {
// If the guess is too low, increase the low index
low = mid + 1;
}
}
// If the item is not found, return -1
return -1;
}
This function uses a binary search algorithm to find the item in the given list. It starts by setting the low
and high
indices to the beginning and end of the list, respectively. It then enters a loop where it continuously divides the search space in half until it finds the item or determines that it's not in the list.
At each iteration of the loop, the function calculates the middle index of the current search space, and compares the item at that index to the target item. If they match, the function returns the index. If the item at the middle index is greater than the target item, the function reduces the search space to the lower half of the list (by setting the high
index to the middle index minus one). Otherwise, it increases the search space to the upper half of the list (by setting the low
index to the middle index plus one).
If the loop ends without finding the item, the function returns -1 to indicate that the item was not found in the list.
My comments
Once again, good job!
Given that ChatGPT is a general purpose tool that wasn't specifically trained for coding problems, it's remarkably accurate when dealing with data structures and algorithms. 🔥
And I'm sure many CS students would use this to cheat on their exams! 😅
Final result: success! ✅
Experiment 4: Play Rock, Paper, and Scissors
Me: Write a Dart program that lets a human play rock, paper, and scissors against the computer. The human can choose each move by typing it from the command line. The computer should choose each move at random.
AI: Here is a sample program in Dart that lets a human play rock, paper, scissors against the computer:
import 'dart:io';
import 'dart:math';
void main() {
// Create a list of moves.
final moves = ['rock', 'paper', 'scissors'];
// Create a random number generator.
final random = Random();
// Play the game.
while (true) {
// Get the human move.
print('Enter your move (rock, paper, or scissors):');
final humanMove = stdin.readLineSync().toLowerCase();
// Check if the human move is valid.
if (!moves.contains(humanMove)) {
print('Invalid move!');
continue;
}
// Get the computer move.
final computerMove = moves[random.nextInt(moves.length)];
print('Computer plays $computerMove');
// Determine the winner.
if (humanMove == computerMove) {
print('It\'s a tie!');
} else if (
(humanMove == 'rock' && computerMove == 'scissors') ||
(humanMove == 'paper' && computerMove == 'rock') ||
(humanMove == 'scissors' && computerMove == 'paper')
) {
print('You win!');
} else {
print('Computer wins!');
}
print();
}
}
In this program, we create a list of moves that the human and the computer can choose from. Then, we use a Random
object to generate random numbers, which we use to choose the computer's moves.
In each round of the game, the human enters their move from the command line, and the computer chooses a move at random. We check if the human's move is valid, and if it is, we determine the winner of the round based on the rules of rock, paper, scissors.
Finally, we print the result of the round and continue to play until the human quits the game.
My comments
The code in the answer seems plausible, and the follow-up explanation is clear and confident.
But is it correct?
At first sight, the code is concise and includes some defensive programming (checking if the human move is valid).
The AI added a game loop (while (true)
) without being prompted. This shows a good understanding of how I might want to play the game.
When a question is not specific enough, ChatGPT will make assumptions about your intention. If you hit "Try again" to get a different answer, it may make different assumptions.
Does the code compile?
Well, I copied it over to a dart file in VSCode, and spotted two compile errors:
final humanMove = stdin.readLineSync().toLowerCase();
// The method 'toLowerCase' can't be unconditionally invoked because the receiver can be 'null'.
print();
// 1 positional argument(s) expected, but 0 found.
The first error is easily fixed by adding a !
since readLineSync()
returns a nullable value:
final humanMove = stdin.readLineSync()!.toLowerCase();
And the second error is fixed by removing the print()
statement altogether (not sure why it was added in the first place).
Lo and behold, the game is now playable! 👇
➜ dart rock_paper_scissors.dart
Enter your move (rock, paper, or scissors):
rock
Computer plays rock
It's a tie!
Enter your move (rock, paper, or scissors):
scissors
Computer plays paper
You win!
Enter your move (rock, paper, or scissors):
paper
Computer plays scissors
Computer wins!
Enter your move (rock, paper, or scissors):
It would have taken me ~15 minutes to write the same program.
Yet ChatGPT got it right on the first try, and I got the code to work in 1 minute with very minor fixes.
Very impressive indeed. 👏
Final result: success! ✅
Experiment 5: Get the Current Weather
Me: Write a Dart program to fetch the current weather for a given city using the OpenWeatherMap API. The input city should be passed as a command line argument.
AI: Here is a simple Dart program that uses the http
package to make a GET request to the OpenWeatherMap API to fetch the current weather for a given city:
import 'package:http/http.dart' as http;
void main(List<String> args) {
if (args.length != 1) {
print("Please provide a city name as a command line argument.");
return;
}
// Replace this with your own OpenWeatherMap API key.
String apiKey = "<your_api_key>";
// Replace this with the correct URL for the OpenWeatherMap API.
String url = "https://api.openweathermap.org/data/2.5/weather?q=${args[0]}&appid=$apiKey";
http.get(url).then((response) {
if (response.statusCode == 200) {
// The API returned a successful response.
print(response.body);
} else {
// The API returned an error.
print("Failed to fetch weather data. Please check your API key and city name and try again.");
}
});
}
In this example, the city name is passed as a command line argument, and the API key is hard-coded into the program. You will need to replace <your_api_key>
with your own API key from OpenWeatherMap.
My comments
At first sight, this looks good!
There is one compile error on this line:
http.get(url).then((response) {
// The argument type 'String' can't be assigned to the parameter type 'Uri'
This is easily fixed using the Uri.parse
method:
http.get(Uri.parse(url)).then((response) {
Most likely, ChatGPT was unaware of a breaking change requiring to pass a Uri
rather than a String
when calling any of the http methods.
ChatGPT claims to be trained with public data up to 2021, and we should keep it in mind if we use APIs with recent breaking changes.
The code style could be improved by using async
/await
rather than .then
, but this can be easily changed by hand.
After adding my API key (as instructed), I ran the program and got this:
➜ dart bin/weather.dart London
{"coord":{"lon":-0.1257,"lat":51.5085},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":278.51,"feels_like":275.38,"temp_min":277.33,"temp_max":279.4,"pressure":1016,"humidity":83},"visibility":10000,"wind":{"speed":4.12,"deg":60},"clouds":{"all":100},"dt":1670156052,"sys":{"type":2,"id":2075535,"country":"GB","sunrise":1670140072,"sunset":1670169228},"timezone":0,"id":2643743,"name":"London","cod":200}
The program works but prints the entire JSON response from the API.
So let's fix this!
Second prompt in thread
Me: Modify this to only print the current temperature.
AI: Here is a modified version of the Dart program that only prints the current temperature from the response from the OpenWeatherMap API:
Note: the output was the same as before, with just one change in the parsing code:
// The API returned a successful response.
var data = json.decode(response.body);
var temperature = data['main']['temp'];
print("The current temperature in ${args[0]} is $temperature degrees.");
In this example, the response body from the API is decoded using the json
package, and the temp
field from the main
section of the JSON data is extracted and printed. This program assumes that the response from the API will be in the correct format and will contain the necessary data. You may need to add additional error handling to handle any unexpected response formats or missing data.
My comments
Very good!
Let's run this again:
➜ dart bin/weather.dart London
The current temperature in London is 278.51 degrees.
Better, but "278.51 degrees" doesn't seem right. I guess I wasn't specific enough with my request.
Third prompt in thread
Me: The output temperature should be in Celsius, not Kelvin.
AI: Here is a modified version of the Dart program that converts the temperature from Kelvin to Celsius before printing it:
Note: the output was the same as before, with just this one change on the parsing code:
// The API returned a successful response.
var data = json.decode(response.body);
var temperature = data['main']['temp'];
var temperatureC = temperature - 273.15;
print("The current temperature in ${args[0]} is $temperatureC degrees Celsius.");
In this example, the temperature is converted from Kelvin to Celsius by subtracting 273.15 from the temperature in Kelvin. This is a simple approximation that assumes a temperature of 0°C is equivalent to 273.15°K, which is a common approximation but may not be accurate at all temperatures. You may need to use a more accurate conversion formula if you require greater precision.
My comments
Spot on!
Here's the output after the last change:
dart bin/weather.dart London
The current temperature in London is 5.360000000000014 degrees Celsius.
At this point, I could have asked the AI to print the temperature as an integer.
But it's clear that ChatGPT remembers the context of the previous conversation and uses it when producing the next answer.
This means that if our initial prompt is not precise enough, we don't need to restart from scratch, and we can get a refined solution by following up with more details.
Overall, this feels like having a dialogue with a competent assistant. 👌
Final result: success! ✅
Experiment 6: CustomPainter
For this experiment, I asked the AI to write some Flutter code using CustomPainter
, since doing this by hand can be time-consuming.
Me: Write a Flutter CustomPainter
that draws a smiling face with two eyes.
AI: Here is an example of a Flutter CustomPainter
that draws a smiling face with two eyes:
class SmilingFacePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint();
// Set the color to blue
paint.color = Colors.blue;
// Create a circle for the face
final center = Offset(size.width / 2, size.height / 2);
final radius = min(size.width / 2, size.height / 2);
canvas.drawCircle(center, radius, paint);
// Create two eyes
final eyeOffset = radius / 3;
final leftEye = Offset(center.dx - eyeOffset, center.dy - eyeOffset);
final rightEye = Offset(center.dx + eyeOffset, center.dy - eyeOffset);
final eyeRadius = radius / 6;
canvas.drawCircle(leftEye, eyeRadius, paint);
canvas.drawCircle(rightEye, eyeRadius, paint);
// Create a smile
final smilePath = Path();
smilePath.moveTo(center.dx - radius / 2, center.dy);
smilePath.quadraticBezierTo(center.dx, center.dy + radius / 2, center.dx + radius / 2, center.dy);
canvas.drawPath(smilePath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
To use this CustomPainter
, you can pass an instance of SmilingFacePainter
to the CustomPaint
widget in your Flutter app.
CustomPaint(
painter: SmilingFacePainter(),
);
This will draw a smiling face with two eyes on the screen. You can customize the appearance of the face by modifying the values in the paint
object, such as the color or the size of the eyes.
My comments
A pretty good start!
After bringing this code into Dartpad I noticed that there is only one small problem:
final radius = min(size.width / 2, size.height / 2);
// The method 'min' isn't defined for the type 'SmilingFacePainter'.
This is easily fixed by importing dart:math
(which can be done using Quick Fix in VSCode):
import 'dart:math';
Here's a Dartpad preview of the code above:
But hang on, where are the eyes and mouth?
As it turns out, they have been drawn but are not visible because they have the same blue color as the face.
Second prompt in thread
Me: Make the face yellow. The eyes and mouth should be red.
AI: To make the face yellow, you can modify the paint.color
property in the SmilingFacePainter
class like this:
paint.color = Colors.yellow;
To make the eyes and mouth red, you can create a new Paint
object with the color set to red and use it to draw the eyes and mouth like this:
class SmilingFacePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint();
// Set the color to yellow for the face
paint.color = Colors.yellow;
// Create a circle for the face
final center = Offset(size.width / 2, size.height / 2);
final radius = min(size.width / 2, size.height / 2);
canvas.drawCircle(center, radius, paint);
// Set the color to red for the eyes and mouth
paint.color = Colors.red;
// Create two eyes
final eyeOffset = radius / 3;
final leftEye = Offset(center.dx - eyeOffset, center.dy - eyeOffset);
final rightEye = Offset(center.dx + eyeOffset, center.dy - eyeOffset);
final eyeRadius = radius / 6;
canvas.drawCircle(leftEye, eyeRadius, paint);
canvas.drawCircle(rightEye, eyeRadius, paint);
// Create a smile
final smilePath = Path();
smilePath.moveTo(center.dx - radius / 2, center.dy);
smilePath.quadraticBezierTo(center.dx, center.dy + radius / 2, center.dx + radius / 2, center.dy);
canvas.drawPath(smilePath, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
This will make the face yellow, and the eyes and mouth red. You can further customize the appearance of the face by modifying the values in the paint
object, such as the size of the eyes or the width of the mouth.
My comments
Nice! Now I just need to update the code and voilà! 🎨
Well done, ChatGPT. I'm proud of you!
Final result: success! ✅
Experiment 7: Declare three routes using the GoRouter package
Me: Suppose I have a Flutter app with three routes: /login
, /home
, and /account
. Declare these routes using the GoRouter package.
AI: To declare routes using the GoRouter package in a Flutter app, you would first need to import the package:gorouter/gorouter.dart
library. Then, you could define the routes as follows:
var router = GoRouter();
router.define('/login', handler: (context) {
// Handle the /login route
});
router.define('/home', handler: (context) {
// Handle the /home route
});
router.define('/account', handler: (context) {
// Handle the /account route
});
Alternatively, you could define the routes using the .add()
method, which allows you to specify additional options for each route, such as the HTTP methods that it supports or the handler function to be called when the route is accessed:
var router = GoRouter();
router.add('/login', methods: ['GET', 'POST'], handler: (context) {
// Handle the /login route
});
router.add('/home', methods: ['GET'], handler: (context) {
// Handle the /home route
});
router.add('/account', methods: ['GET', 'PUT'], handler: (context) {
// Handle the /account route
});
Once you have defined your routes, you can use the router.run()
method to start the router and listen for incoming requests. For example:
router.run();
This will start the router and allow it to handle requests to the defined routes. You can then use the router.navigateTo()
method to navigate to a specific route within your Flutter app. For example:
router.navigateTo('/login');
This will navigate to the /login
route and call the corresponding handler function.
My comments
Completely wrong!
I guess ChatGPT doesn't know about GoRouter and just tried to guess the answer based on some (server-side?) routing package outside the Flutter ecosystem.
In this case, ChatGPT is useless, and not suited for the task.
Final result: fail! ❌
Experiment 8: Write a Firebase Cloud Function
Since ChatGPT is proficient with many languages, I decided to move away from Dart & Flutter and ask it to write a Cloud Function.
Me: Write a Firebase Cloud function that is triggered when any document inside a /product/{pid}/reviews
collection changes. The function should calculate the average review score and write it back as an avgRating
field inside the /product/{pid}
document.
AI: Here is an example of a Firebase Cloud Function that is triggered when a document inside a /product/{pid}/reviews
collection changes. This function calculates the average review score and writes it back as an avgRating
field inside the /product/{pid}
document:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.calculateAverageRating = functions.firestore
.document('/product/{pid}/reviews/{reviewId}')
.onWrite(async (change, context) => {
// Get the product ID from the context
const pid = context.params.pid;
// Get a reference to the reviews collection
const reviewsRef = admin
.firestore()
.collection('/product/' + pid + '/reviews');
// Get all the reviews for the product
const reviewsSnapshot = await reviewsRef.get();
// Calculate the average rating
let totalRating = 0;
let numRatings = 0;
reviewsSnapshot.forEach(review => {
totalRating += review.data().rating;
numRatings++;
});
const avgRating = totalRating / numRatings;
// Get a reference to the product document
const productRef = admin.firestore().doc('/product/' + pid);
// Update the product document with the average rating
return productRef.update({ avgRating: avgRating });
});
This function listens for changes to any document in the /product/{pid}/reviews
collection using a wildcard {pid}
and {reviewId}
in the path. When a change is detected, the function gets a reference to the /product/{pid}/reviews
collection and retrieves all the reviews for the product. It then calculates the average rating by summing up all the ratings and dividing by the number of ratings. Finally, the function gets a reference to the /product/{pid}
document and updates it with the avgRating
field.
My comments
The code compiles, so it's a good start!
I haven't tried running it, but I think ChatGPT got a few things right:
- how to write a trigger to update a document
- extracting parameters from the context
- calculating the average rating
- writing it to the correct document
I wasn't too fond of the imports at the top, so I followed up with this. 👇
Second prompt in thread
Me: Can you use module imports rather than require
?
AI: Yes, you can use module imports rather than require
in JavaScript. Here is an example of how you might import the firebase-functions
and firebase-admin
modules in your Firebase Cloud Function:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
// Rest of the Cloud Function code goes here...
In this example, we are using the import * as
syntax to import the entire module and assign it to a variable named functions
and admin
. You can then use the imported functions and classes from the firebase-functions
and firebase-admin
modules by referencing them through the functions
and admin
variables.
My comments
This thing is lit! 🔥
Final result: success! ✅
Experiment 9: How to seed Cloud Firestore with some test data?
Me: How can I seed Cloud Firestore with some test data?
AI: To seed Cloud Firestore with test data, you can use the Firebase CLI to write data directly to your database. First, make sure that the Firebase CLI is installed on your machine. Then, use the following steps to seed your database:
- Navigate to the directory where your Firebase project is stored.
- Run the
firebase login
command to authenticate the Firebase CLI with your Google account.
- Run the
firebase database:get
command to retrieve the current data in your database. This will create a local file calleddatabase.json
in your project directory, which you can use as a starting point for your test data.
- Edit the
database.json
file to add the test data that you want to seed your database with. Make sure to follow the proper JSON syntax and structure when adding data to this file.
- Once you have added your test data, run the
firebase database:set
command to write the data to your database.
- You can verify that your test data has been added to your database by running the
firebase database:get
command again, which will retrieve the current data in your database and print it to the console.
That's it! You have successfully seeded your Cloud Firestore database with test data.
My comments
While the answer sounds plausible, it is wrong!
According to the docs, database:get
is indeed a valid command, but it only works on Firebase Realtime Database, and there is no equivalent for Cloud Firestore.
I told my friendly assistant about it, but it answered with commands like firestore:set
and firestore:add
that don't actually exist.
And it kept giving wrong answers with confidence. 🙄
Final result: fail! ❌
Final Results and Evaluation
I must say I'm very impressed by the natural language processing skills of ChatGPT. Clearly, the AI did understand every single question, and that in itself is a very remarkable feat!
Beyond that, ChatGPT managed to score 7 out of 9 points and proved valuable in all these areas:
- Detect and correct common coding errors
- Explain how code works
- Write or complete code to solve a given task
ChatGPT failed two tasks, showing that it is not up to date with the latest packages and APIs, and it kept giving wrong answers when prompted.
But on the remaining tasks, I was very impressed with the explanations and thought the code was pretty good.
Some minor syntax errors were present, but they were easy to fix, and I got the code to work much faster than if I had written it by hand.
Some reflections on ChatGPT and a word of caution
After spending more time getting acquainted with ChatGPT, I would summarise as follows:
- ChatGPT always gives answers that look plausible in a very confident tone, even when they are wrong.
- It is very good at answering specific questions where the solution is not too complex.
- It is particularly good with questions about data structures and algorithms (you know, those that always pop up during tech interviews 😎).
- It clearly doesn't know the latest APIs (I asked questions about GoRouter, Riverpod, and other packages, and it was completely off-mark).
- It can explain code in a lot of detail.
- If you ask generic questions, you'll get generic answers that lack insight (try asking about state management or app architecture and you'll see).
If you're working on simple, well-defined, and self-contained tasks based on data that ChatGPT was trained on, a ChatGPT-based workflow can be 10x faster than coding the solution by hand. And this is quite remarkable!
ChatGPT is good enough at writing pure Dart code (such as business logic) that doesn't rely on APIs and frameworks. Since it "knows" all the mainstream programming languages, it can definitely help you in areas where you're not an expert, especially when you're writing new code.
But when you're working on existing code, you need a lot of context about how the system works as a whole, and an AI model trained on public code is unlikely to be of much help.
Be particularly careful if you use ChatGPT with dynamically typed languages that don't give you any compile-time guarantees. If the answer is wrong, you'll only find out at runtime, and we all know how fun that is.
ChatGPT can be helpful but unreliable, so keep this in mind:
ChatGPT is "just" an assistant, and you are responsible for ensuring the code is correct! 🫵
In fact, ChatGPT is not an authoritative source like a high-quality tutorial or official documentation.
Though, as Daniel Vassallo pointed out on Twitter:
One problem with getting answers from ChatGPT is that the AI has no skin in the game. No credibility, no reputation to protect, no pride in giving you the best answer, no consequences if its answers cause you harm. The source of the answer is as important as the answer.
Making the most of ChatGPT with Prompt Engineering
To make the most of ChatGPT and other AI tools, you need to get good at prompt engineering. But what role will AI play in the future?
Will AI take your job away?
Developer tools are getting better and better.
In addition to compilers, debuggers, static analyzers, language servers, and powerful IDEs, we now have the power of AI at our disposal.
AI can help us ship better software faster if we learn to use it strategically, and for now, ChatGPT and GitHub Copilot can help us solve basic programming problems.
But as AI continues to get better, we have to wonder:
- Will it take our jobs away?
I'll quote Fireship on this one, as he has already made some great videos about GitHub Copilot and ChatGPT. This is his take:
- Step 1 - developers share code data
- Step 2 - build an AI with that data
- Step 3 - reinforce the AI with developers
- Step 4 - replace developers with AI
It seems that we are squarely at step 3 today, and I hear GPT-4 is just round the corner.
To find out what will really happen, I decided to ask one last question to ChatGPT. 👇
That was obviously made up. If you wanna hear what a real expert thinks about AI, check this podcast where Lex Friedman asked John Carmack about AGI (and much more).
I guess we'll wait and see. 😅
Happy coding!
References
To better understand how ChatGPT works and what it can do, I found these resources helpful: