Infix operator labeling

With what? What did the search fail with?

It’s a cliffhanger ending!

Hmm. I mean, there is no method Array.head – that comes implicitly via ArrayOps. I wonder if the implicit conversion has somehow gotten hosed…

Whoops, sorry. Here is the full error message:

[error] -- [E008] Not Found Error: /home/rpaielli/trajspec/src/main/FlightInfo.scala:18:52 
[error] 18 |  val airportCode = AirportCode(txt.trim.split("/").head)
[error]    |                                ^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |value head is not a member of Array[String].
[error]    |Extension methods were tried, but the search failed with:
[error]    |
[error]    |    method RoutePts1 needs result type because its right-hand side attempts implicit search

This makes no sense to me for two reasons. First, I don’t see the connection between RoutePts1 and Array.head. Secondly, RoutePts1 is not a method. It is a dummy name for an implicit class:

type RoutePts = Vector[RoutePt]

implicit class RoutePts1(points: RoutePts):
...

If it matters, here is the definition of RoutePt:

case class RoutePt( // route point: along/cross-track position relative to route
  time: Scalar = zero, // time
  dist: Scalar = zero, // along-track distance on route
  alt: Scalar = zero, // altitude
  cross: Scalar = zero // cross-track position (+right, -left)
  ):
...

Again, this is all code that has worked fine for years.

Step back a bit…

  1. Your code hasn’t changed since you upgraded and then downgraded the Scala version - correct?
  2. Double checking, does the current form of the code base build cleanly on a completely different computer?
  3. Can you share the code base so that someone else can verify this?
  4. Have you tried running a Scala worksheet or REPL or just a temporary bit of code in your project with just “”.trim.split("/").head on your current computer? How about Array(0).head?

Regarding Coursier, even though you may not use it explicitly, I think that SBT uses it internally. If not, then there are also Ivy and possibly even Maven storage locations to check as well - .ivy and .m2 in your home directory.

implicit class C(x) adds an implicit def C(x): C that actually does the conversion.

The error is a generic “cyclic reference” error, which often happens during implicit search just because of the way types are searched. When a “cycle” is detected, it stops the implicit search, which is why you don’t see the “enriched Array” method anymore.

One could “imagine” something like that succeeding in a “partial build” as opposed to a “clean build”, if some classes were pre-compiled. So if “used to work” means “hasn’t been built from scratch in years”, that hypothetical is not unimaginable. (It could be a bug in incremental compilation where the pre-compiled class should have been re-compiled but wasn’t.)

ha, the forum just told me to take it off-line:

You’ve replied to @Russ 3 times, did you know you could send them a personal message instead?

Thanks for clarifying that! And thanks to the others who replied too. That gives me something to look for and relieves me of the fear that I may have been cursed by a witch or some such thing!

A clearer error message might have been helpful. If the compiler can tell that the problem is the result of a cyclic reference in resolving implicit conversions, that might be worth mentioning in the error message.

I may not have done a clean recompile for months, but certainly nowhere near a year or even six months.

I guess the first thing I should try is to convert that implicit class into a regular case class. It was a toss-up as to whether I should use an implicit class in the first place. I may have to do the same thing for other implicit classes too.

Shouldn’t I be able to revert back to an earlier version that way?

This sort of thing is why I use Git to manage even short-lived personal projects — literally even as short-lived as some sample code I spend an hour fooling with.

It’s also why for any project that lasts more than a few days, I push it to GitHub with a GitHub Actions config that at least verifies that the code compiles and usually runs at least one kind of overall system test. Every green CI run of every commit I push becomes a known-good state that I can always revert to later.

I know you didn’t ask for this advice and it might seem like scolding, but honestly, personally, I don’t know how I lived without these tools. This way of working has more than repaid me the small extra effort involved — over and over and over and over again, over the years.

3 Likes

You are probably right, but I am not particularly proficient with git. I am not a software engineer per se but an aeronautical research engineer with a focus on air traffic control automation. I have a fairly unconventional job in that I do my own programming to develop a prototype of my own ideas, then I publish technical papers about it. It’s a dream job for a nerd, I guess. I am much closer to the end of my career than the start, by the way. I barely use git, and I have virtually no experience using it to work with a team. I use add, commit, status, diff and not much else. I also regularly store complete dated copies of my entire codebase in case I need to refer back to them. (I realize that git does that, but I often find it simpler to refer back to those snapshots.)

I decided to use Scala many years ago because I read some articles about it and it seemed elegant and expressive. Unfortunately, however, few if any of my colleagues are using it, so I have no one to consult with other than this group, for which I am very grateful, of course. But when it comes to tools such as git or an IDE, when I get stuck I usually just drop it and continue doing things the old-fashioned way. You wouldn’t believe how many times I’ve tried to start using one IDE or another but got stuck and reverted back to emacs.

In the past, I have had periods in which, for various reasons, I carelessly neglected to make git commits for too long – days or even weeks. Then a major bug popped up, and I had a very hard time tracking it down due to insufficient git records. That gave me an idea of having sbt automatically record an uncommented commit in the background every time a compilation succeeds. That would allow the careless user like me to use a simple bisection method to easily track down the change that caused the bug. What do you think about that idea? Has it ever been proposed or tried?

1 Like

You don’t need to be. You just need the super basics. commit and push is good enough for solo project (you don’t need branches and all that complicated stuff). Being proficient in Emacs is waaaay harder! If you can do that, you can definitely do this.

It’s really more about building habits rather than proficiency with git. Many people miss this important point.

It sounds like you just need to get over “the initial hump”. It’s just like brushing teeth or flossing, really! Habit formation. Unfortunately old dogs do need to learn new tricks. It’s not good to remain stuck in old ways. Flexibility is important!

In fact you can use a free GUI if you want, that’s what I do:

This lets you choose an earlier commit and revert to it in a very clear, visual way.

SGTM. I haven’t seen or heard of an sbt-specific solution for that, but googling “automatically commit to git” or some such shows some shell-based solutions.

But I think you might get nearly as much value from setting an automatic reminder (using a calendar app, or to-do app, or whatever) to commit daily.

2 Likes

I’ve thought about this lately but haven’t done it. You could even have an AI write the commit message. One way, using GitHub - Nutlope/aicommits: A CLI that writes your git commit messages for you with AI, is to do it is something like this:


val aiCommit = taskKey[Unit]("Commit with AI-generated message")

aiCommit := {
  import scala.sys.process._
  compile.value
  "aicommits --all".!
}

Then, instead of running sbt ~compile you’d run sbt ~aiCommit.

I’m not sure if that will commit non-interactively. Normally I think it asks for confirmation. You could also try GitHub - di-sukharev/opencommit: Auto-generate impressive commits with AI in 1 second 🤯🔫 or GitHub - insulineru/ai-commit: ✨ Make commits easier with ChatGPT, Gitmoji and Conventional Commits 🚀 (that has a --force).

For most projects one would want to squash commits after doing that for a while, and edit the commit messages.

Another option might be to give Git Butler a try.

2 Likes

I don’t have anyone around me (who do any programming at all, in any language) either. I use Scala purely as a hobby, but I’ve already become a “regular”, and even contributed a tiny bit.

So the community is super welcoming, the more you hang out the more you learn. Come hang out with us more. Drop by Discord! You can bounce off ideas much more effectively there.

That an interesting idea, but I personally wouldn’t worry about generating comments for automated commits. For my purposes, comments on the manual commits should be more than sufficient.

I think of automatic commits as analogous to the way google docs works. With google docs, you never have to explicitly “save” the document. It automatically keeps track of all the changes. It seems that some combination of git and sbt should be able to do something similar.

As for commit comments, I will confess that I am often careless with them. As an individual developer who does not work with a team, they often seem like more of a nuisance than they are worth to me.

Sometimes I get into deep, time-consuming (days long) debugging or refactoring sessions, and my head is spinning with all the complexity I am trying to keep track of. Then when I finally find the bug or get things working properly, I go to commit the code. But when it comes to writing the commit comment, I am often at a complete loss as to what to write until I think about it for a while. I’m guessing that’s not a good sign.

That’s fair, and we’re all tempted that way sometimes. But it’s worth remembering that the confused other developer who is trying to figure out what the heck you intended is yourself, a year later.

Also not at all unusual. My rule of thumb is to focus on what I was trying to accomplish. A sentence or two of that is usually most of what matters; I try not to over-think it too much beyond that.

But I think you might get nearly as much value from setting an automatic reminder (using a calendar app, or to-do app, or whatever) to commit daily.

There have been times during a large refactoring or a difficult debugging phase in which my code did not compile for days. That’s usually how I get behind on commits, resulting eventually in a large commit with too many changes. Are you suggesting that I should I commit daily even if my code does not compile?

Hmm… I think a reasonable working style could go either way? I might use the commit message to distinguish “good” for “bad” commits, in that case.

But if the git skills you’re willing to acquire include branching and/or squashing, read on…

You could do a large refactoring like that on a branch, or do it on the main branch but then once you’re done, squash all your broken commits into a single working commit that contains the entire refactoring.

In practice, branching before I begin something substantial is what I personally do.