Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Using a Factory Pattern

stutzbach
Beginner
405 Views

Hello,

I have a problem with a code using a factory pattern. The compiler reports a error i do not know how to fix.
I using the Intel Visual Fortran Composer XE 2011 12.0.3470.2010.
Error: error #8314: If the rightmost part-name is of abstract type, data-ref shall be polymorphic [CREATEWORKINGMODEL] in main.f90 line 15.
Perhaps someone knows how to fix this error?

Greetings Moritz

PROGRAM main

USE workingmodel_factory

IMPLICIT NONE

CHARACTER(len=20) :: string

TYPE(cfactory) :: factory

CLASS(workingmodel), POINTER :: pworkingmodel => null()

string = 'H'

CALL factory%init(string)

pworkingmodel => factory%createworkingmodel()

CALL pworkingmodel%description()

END PROGRAM main



MODULE workingmodel_factory

USE tcH

IMPLICIT NONE

TYPE cfactory

PRIVATE

CHARACTER(len=20) :: chfactory

CLASS(workingmodel), POINTER :: pworkingmodel

CONTAINS

PROCEDURE :: init

PROCEDURE :: createworkingmodel

END TYPE cfactory

CONTAINS

SUBROUTINE init(this, string)

CLASS(cfactory), INTENT(INOUT) :: this

CHARACTER(len=*), INTENT(IN) :: string

this%chfactory = trim(string)

this%pworkingmodel => null()

END SUBROUTINE init

FUNCTION createworkingmodel(this) RESULT(ptr)

CLASS(cfactory) :: this

CLASS(workingmodel), POINTER :: ptr

IF (this%chfactory == 'H') THEN

IF (ASSOCIATED(this%pworkingmodel)) DEALLOCATE(this%pworkingmodel)

ALLOCATE(tH :: this%pworkingmodel)

ptr => this%pworkingmodel

ELSEIF (this%chfactory == 'Z') THEN

IF (ASSOCIATED(this%pworkingmodel)) DEALLOCATE(this%pworkingmodel)

ALLOCATE(tZ :: this%pworkingmodel)

ptr => this%pworkingmodel

END IF

END FUNCTION createworkingmodel

END MODULE workingmodel_factory


MODULE tcH

USE extensions

IMPLICIT NONE

TYPE, EXTENDS(workingmodel) :: tH

CONTAINS

PROCEDURE, PASS(this) :: description => h_desc

END TYPE tH

CONTAINS

SUBROUTINE h_desc(this)

CLASS(tH), INTENT(IN) :: this

WRITE(*,*) 'H'

END SUBROUTINE h_desc

END MODULE tcH


MODULE extensions

IMPLICIT NONE

TYPE, ABSTRACT, PUBLIC :: workingmodel

CONTAINS

PROCEDURE(generic_desc),PUBLIC, PASS(this), DEFERRED :: description

END TYPE workingmodel

ABSTRACT INTERFACE

SUBROUTINE generic_desc(this)

IMPORT :: workingmodel

CLASS(workingmodel), INTENT(IN) :: this

END SUBROUTINE generic_desc

END INTERFACE

TYPE, EXTENDS(workingmodel) :: tZ

CONTAINS

PROCEDURE, PASS(this) :: description => z_desc

END TYPE tZ

CONTAINS

SUBROUTINE z_desc(this)

CLASS(tZ), INTENT(IN) :: this

WRITE(*,*) 'Z'

END SUBROUTINE z_desc

END MODULE extensions

0 Kudos
1 Reply
IanH
Honored Contributor III
405 Views
I think it is a compiler bug. See this post.

A work around is to make your factory procedure a subroutine rather than a function, i.e:

[fortran]  SUBROUTINE createworkingmodel(this, ptr)
    CLASS(cfactory) :: this
    CLASS(workingmodel), INTENT(OUT), POINTER :: ptr
    ...[/fortran]

Otherwise, if you get => and = mixed up, all sorts of wonderful, mysterious, but ultimately painful things will start happening in your program.

As an aside, if I was writing to the factory pattern I would have a abstract parent type for the factory as well, and then extensions of that type to actually create the objects, rather than a big switch statement. Alternatively, the string that designates the type of object to be created would be an argument to the createworkingmodel routine.
0 Kudos
Reply