Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type mismatch when using JavaMailEmil #216

Closed
gabriellemadden opened this issue Jun 17, 2021 · 2 comments
Closed

Type mismatch when using JavaMailEmil #216

gabriellemadden opened this issue Jun 17, 2021 · 2 comments

Comments

@gabriellemadden
Copy link

I'm trying to use the JavaMailEmil class to write a program, but when I try to call emil.run, I get a type mismatch. See the following code:

val emil = JavaMailEmil[Task](blocker)
val imapConf: MailConfig =
  MailConfig(myEmail.server, myEmail.user, myEmail.password, SSLType.SSL)

val access: Access[Task, JavaMailConnection] = new AccessImpl[Task](blocker)

def searchInbox: MailOp[Task, JavaMailConnection, SearchResult[Mail[Task]]] =
  for {
    inbox <- access.getInbox
    emails <- access.searchAndLoad(inbox, 1)(
      (Subject contains "MySubject")
    )
  } yield emails

emil(imapConf).run(searchInbox /* Type mismatch here */ ) 

This is the type mismatch, where emil.run is expecting an emil.C connection instead of a JavaMailConnection for MailOp:
Screen Shot 2021-06-17 at 10 34 48 AM

I looked into the JavaMailEmil apply method and found that it is returning type Emil rather than type JavaMailEmil. I published a version of your lib locally where I changed the apply function to return type JavaMailEmil and type mismatches go away, everything compiles and runs like a dream.

  • If Emil is the return type on purpose, can you tell me what I'm doing wrong so I can implement it correctly? I'm not sure why it would need to return an Emil type when we already know it extends the Emil trait
  • Otherwise, I can make a pull request fixing the apply method return type.

Thanks so much!

@eikek
Copy link
Owner

eikek commented Jun 17, 2021

Hi @gabriellemadden ,

yeah, this is a bit tricky, because the type for the connection must match the one inside the concrete instance of Emil. In general your code that works on mails (like searchInbox) doesn't need to know the specific type of connection, which is a JavaMailConnection here. This code works for other connections as well, as long as it is executed using the corresponding instance of Emil. Now, there is no other implementation yet, but should you move searchInbox into another module, it wouldn't need a dependency on emil-javamail (and thus no dependency on javamail).

The recommended way is to create the Emil instance, just as you did, but then use it to obtain the Access instance via emil.access. Try to stay away from classes in the internal package, they shouldn't be needed in almost all cases. If you do this, then the type mismatch happens already in that line :). The trick is to use a type C that is defined on the instance emil:

val access: Access[Task, emil.C] = emil.access

def searchInbox: MailOp[Task, emil.C, SearchResult[Mail[Task]]] =
  for {
    inbox <- access.getInbox
    emails <- access.searchAndLoad(inbox, 1)(
      (Subject contains "MySubject")
    )
  } yield emails

emil(imapConf).run(searchInbox)

But this also ties your searchInbox code to some concrete C - that's totally fine for examples or when you simply don't care about being more generic. However, in general I would rewrite it a little to pass in the Access instance like this:

def searchInbox[C](access: Access[Task, C]): MailOp[Task, C, SearchResult[Mail[Task]]] =
  for {
    inbox <- access.getInbox
    emails <- access.searchAndLoad(inbox, 1)(
      (Subject contains "MySubject")
    )
  } yield emails

emil(imapConf).run(searchInbox(emil.access))

This frees you a bit from worring about this Connection type, be it JavaMailConnection or something else. The argument defines what C to use here and this is "hidden" in the concrete instance of Emil that you use at the end. The searchInbox would then also work with other instances of Emil should they exist some day :-).

The return type is on purpose. It could return the more specific type, too. I did not choose this, so the user needs to code against the abstract type Emil and not accidentally against the JavaMailEmil, which I thought should not be necessary.

Hope this helps and hope I was not too confusing….

@gabriellemadden
Copy link
Author

@eikek amazing, I was struggling with the generic bit but it's much more clear now after getting access out of emil itself! Everything looks a lot better without depending on an implementation. Thanks so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants