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

isInstanceOf problem with multiple impl #131

Open
griffith1deady opened this issue Mar 7, 2024 · 4 comments
Open

isInstanceOf problem with multiple impl #131

griffith1deady opened this issue Mar 7, 2024 · 4 comments

Comments

@griffith1deady
Copy link

griffith1deady commented Mar 7, 2024

Hello! I'm glad you added this feature, but currently this work only for this case:

import oolib

protocol Launchable:
    proc prepareForLaunch()
    proc launch()
    proc stop()

protocol HotCompilable:
    proc configureReloading()

class ServerLaunchable impl (Launchable):
    proc prepareForLaunch = discard
    proc launch = discard
    proc stop = discard
    proc configureReloading = discard

let serverLaunchable = ServerLaunchable.new()
echo serverLaunchable.isInstanceOf(Launchable) #true
echo serverLaunchable.isInstanceOf(HotCompilable) #false

and not for this:

import oolib

protocol Launchable:
    proc prepareForLaunch()
    proc launch()
    proc stop()

protocol HotCompilable:
    proc configureReloading()

class ServerLaunchable impl (Launchable, HotCompilable):
    proc prepareForLaunch = discard
    proc launch = discard
    proc stop = discard
    proc configureReloading = discard

let serverLaunchable = ServerLaunchable.new()
echo serverLaunchable.isInstanceOf(Launchable) #false
echo serverLaunchable.isInstanceOf(HotCompilable) #false
@griffith1deady griffith1deady changed the title isInstanceOf problem with multiple impl isInstanceOf problem with multiple impl Mar 7, 2024
@griffith1deady
Copy link
Author

griffith1deady commented Mar 8, 2024

Tryed rewrite code for checking like this:

macro isInstanceOf*(value: typed, protocol: typed): bool =
  let protocolDefinition = if ProtocolTable.hasKey(protocol.strVal):
    protocol
  else:
    newEmptyNode()

  if protocolDefinition.kind == nnkEmpty: return newLit(false)
  
  let protocolImpl = getImpl(protocol)

  for protocolFieldIndex, protocolFieldNode in protocolImpl[2]:
      let protocolParameterName = if protocolFieldNode.kind == nnkIdent: protocolFieldNode[0].strVal else: repr(protocolFieldNode[0])
      let protocolParameterType = protocolFieldNode[1]

      let destinationImpl = if value.kind == nnkObjConstr: getImpl(value[0]) else: getImpl(getImpl(value)[2][1])
      var isValid = false

      for destinationFieldIndex, destinationFieldNode in destinationImpl[2][0][2]:
        let parameterName = if destinationFieldNode.kind == nnkIdent: destinationFieldNode[0].strVal else: repr(destinationFieldNode[0])
        let parameterType = destinationFieldNode[1]

        isValid = isValid or (protocolParameterName == parameterName) and (protocolParameterType == parameterType)

      result = newLit(isValid)

but seem's like procedures not stored like destination proc fields, and then from your side need make CacheTable like [Destination, seq[proc]], where destination - generated type for protocol impl, and seq[proc] is implemented procedures

@griffith1deady
Copy link
Author

griffith1deady commented Mar 8, 2024

For example, my idea works with that code:

macro isInstanceOf*(value: typed, protocol: typed): bool =
  let protocolDefinition = if ProtocolTable.hasKey(protocol.strVal):
    protocol
  else:
    newEmptyNode()

  if protocolDefinition.kind == nnkEmpty: return newLit(false)
  
  let protocolImpl = getImpl(protocol)
  var isValidDestination = false

  for protocolFieldIndex, protocolFieldNode in protocolImpl[2]:
      let protocolParameterName = if protocolFieldNode.kind == nnkIdent: protocolFieldNode[0].strVal else: repr(protocolFieldNode[0])
      let protocolParameterType = protocolFieldNode[1]

      let destinationImpl = if value.kind == nnkObjConstr: getImpl(value[0]) else: getImpl(getImpl(value)[2][1])
      for destinationFieldIndex, destinationFieldNode in destinationImpl[2][0][2]:
        let parameterName = if destinationFieldNode.kind == nnkIdent: destinationFieldNode[0].strVal else: repr(destinationFieldNode[0])
        let parameterType = destinationFieldNode[1]

        isValidDestination = isValidDestination or (protocolParameterName == parameterName) and (protocolParameterType == parameterType)

  if result.kind == nnkEmpty:
    result = newLit(isValidDestination)
  elif result.kind == nnkSym:
    let storedValue = result.boolVal
    if storedValue and not isValidDestination:
      return newLit(false)

and then testing code:

import oolib

protocol Launchable:
    proc prepareForLaunch()
    proc launch()
    proc stop()

protocol HotCompilable:
    proc configureReloading()

protocol Understable:
    proc idk()

class ServerLaunchable impl (Launchable, HotCompilable):
    proc prepareForLaunch = discard
    proc launch = discard
    proc stop = discard
    proc configureReloading = discard

type IDK = ref object
    configureReloading: proc()
    idk: proc()

let serverLaunchable = ServerLaunchable.new()

echo IDK().isInstanceOf(HotCompilable) #true
echo IDK().isInstanceOf(Understable) #true
echo IDK().isInstanceOf(Launchable) #false
echo serverLaunchable.isInstanceOf(Launchable) #false
echo serverLaunchable.isInstanceOf(HotCompilable) #false
echo serverLaunchable.isInstanceOf(Understable) #false
echo serverLaunchable.isInstanceOf(string) #false 

@glassesneo
Copy link
Owner

glassesneo commented Mar 11, 2024

Thank you for letting me know this issue, I've completely forgotten about multiple implementation.
I was unsure of how to proceed, but I now realize making protocols with custom pragma can be an easier solution. This will allow isInstanceOf to read their names to check whether an instance matches a type.

protocol P:
  ...

protocol P2:

class C impl (P, P2):
  ...

# will be converted to below

type P = tuple
  ...

type C {.derive: ["P", "P2"].} = ref object
  ...

@griffith1deady
Copy link
Author

What's the status about this?

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