Sign in to follow this  
Followers 0
FuryCell

Global Vars

31 posts in this topic

#1 ·  Posted (edited)

Is this a bug or a feature? I just want to be sure before i file an issue on the tracker. $Countdown becomes -1.

Global $CountDown=5
Global $CountDown=$CountDown-1
MsgBox(0,"",$CountDown)

It could make sense that Global would clear $countdown before it assigns it but IMHO this is counterintuitive.

Edit:Made the example shorter.

Edited by P5ych0Gigabyte

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.

Share this post


Link to post
Share on other sites



It's a feature.

This means that the Global declaration is being ignored in favor of your newly declared variable.

Interesting. Well I found a fix.

Global $CountDown=5
AdlibRegister("CountDown",1000)

While 1
    Sleep(100)
WEnd

Func CountDown()
    Global $CountDown
    $CountDown=$CountDown-1
    ToolTip($CountDown,0,0)
    If $CountDown=1 then Exit
EndFunc

HKTunes:Softpedia | GoogleCodeLyricToy:Softpedia | GoogleCodeRCTunes:Softpedia | GoogleCodeMichtaToolsProgrammer n. - An ingenious device that turns caffeine into code.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Same thing if you declare them locally.

Local $CountDown=5
Local $CountDown=$CountDown-1
MsgBox(0,"",$CountDown)

And it's the same as:

Local $CountDown = $CountDown - 1
MsgBox(0,"",$CountDown)

Edit:

Interesting. Well I found a fix.

Global $CountDown=5
AdlibRegister("CountDown",1000)

While 1
    Sleep(100)
WEnd

Func CountDown()
    Global $CountDown
    $CountDown=$CountDown-1
    ToolTip($CountDown,0,0)
    If $CountDown=1 then Exit
EndFunc

Hmmm.. ?

Global $CountDown=5
AdlibEnable("CountDown", 1000)

While 1
    Sleep(100)
WEnd

Func CountDown()
    $CountDown=$CountDown-1
    ToolTip($CountDown,0,0)
    If $CountDown=1 then Exit
EndFunc

Excuse for AdlibEnable. Old version.

Edited by Manadar

Share this post


Link to post
Share on other sites

No. Then it's not accessible outside of the script it's declared in. If you have an include that is expecting a globally declared variable, it won't find it.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I was under the impression that a variable declared without the global keyword wasn't available to includes.

I was wrong.

test.au3:

#include "testinclude.au3"
Global $global = "Hi there"
$notGlobal = "Hello"
Test()

testinclude.au3:

Func Test()
MsgBox(0,"Test", $global)
MsgBox(0,"Test", $notGlobal)
EndFunc
Edited by JRowe

Share this post


Link to post
Share on other sites

I found this behavior while trying to assign a global var to a local var, with the same name.

Global $a = 1
Test()
Func Test()
    Local $a = $a
    MsgBox(0,"",$a)
EndFunc

With must declare vars option is on,

Opt("MustDeclareVars", 1)

..you'll get an error. I didn't report this because when I tested it in C, the same thing happened. Maybe it's just normal.


Hi ;)

Share this post


Link to post
Share on other sites

There's a very simple solution to all this: Don't use global variables. That's not entirely true because AutoIt more or less forces you to use global variables for a lot of stuff. However, proper hiding the variable behind an API makes them safe.

1 person likes this

Share this post


Link to post
Share on other sites

I was under the impression that a variable declared without the global keyword wasn't available to includes.

There is no file scope in AutoIt. It's simply a matter of copy-pasta.

Share this post


Link to post
Share on other sites

I think I know the problem, and it has nothing to do with Global or Local thingy. It's because we all forget that:

Global $a = 1

is actually

Global $a
$a = 1

Thus..

Global $CountDown=5
Global $CountDown
$CountDown = $CountDown - 1
MsgBox(0,"",$CountDown)

Does it make any sense?


Hi ;)

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

Why don't you guys spend your time trying to learn how to avoid the use of global variables instead of wasting it trying to figure out exactly how global variables work?

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

GUI stuff is one of the places where global variables pretty much have to be used in AutoIt - at least if you want to use event mode. A simple sample GUI using only a single global variable (and an enumeration) would be:

#include <GUIConstants.au3>
Opt("GUIOnEventMode", 1)

Enum $GUI_HWND, $GUI_CLOSEBUTTON, $GUI_MAX
Global $g_aGUI[$GUI_MAX]

CreateGUI()
GUISetState(@SW_SHOW, $g_aGUI[$GUI_HWND])
WaitForClose()

Func CreateGUI()
    $g_aGUI[$GUI_HWND] = GUICreate("GUI")
    $g_aGUI[$GUI_CLOSEBUTTON] = GUICtrlCreateButton("Close", 5, 5, 50, 25)
    GUICtrlSetOnEvent($g_aGUI[$GUI_CLOSEBUTTON], "OnClose")
    GUISetOnEvent($GUI_EVENT_CLOSE, "OnClose")
EndFunc ; CreateGUI()

Func WaitForClose()
    While WinExists($g_aGUI[$GUI_HWND])
        Sleep(50)
    WEnd
EndFunc ; WaitForClose()

Func OnClose()
    GUIDelete($g_aGUI[$GUI_HWND])
EndFunc ; OnClose()

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

That's really not an API. An API would be more like this:

#include <GUIConstants.au3>
Opt("GUIOnEventMode", 1)

Enum $GUI_HWND, $GUI_CLOSEBUTTON, $GUI_MAX
Global $g_aGUI[$GUI_MAX]

CreateGUI()
GUISetState(@SW_SHOW, GUI_GetHWND())
WaitForClose()

Func CreateGUI()
    GUI_SetHWnd(GUICreate("GUI"))
    GUI_SetCloseButton(GUICtrlCreateButton("Close", 5, 5, 50, 25))
    GUICtrlSetOnEvent(GUI_GetCloseButton(), "OnClose")
    GUISetOnEvent($GUI_EVENT_CLOSE, "OnClose")
EndFunc ; CreateGUI()

Func WaitForClose()
    While WinExists(GUI_GetHWND())
        Sleep(50)
    WEnd
EndFunc ; WaitForClose()

Func OnClose()
    GUIDelete($g_aGUI[$GUI_HWND])
EndFunc ; OnClose()

#Region API

Func GUI_SetHWND($hWnd)
    $g_aGUI[$GUI_HWND] = $hWnd
EndFunc ; GUI_SetHWnd()

Func GUI_GetHWND()
    Return $g_aGUI[$GUI_HWND]
EndFunc ; GUI_GetHWND()

Func GUI_SetCloseButton($id)
    $g_aGUI[$GUI_CLOSEBUTTON] = $id
EndFunc ; GUI_SetCloseButton()

Func GUI_GetCloseButton()
    Return $g_aGUI[$GUI_CLOSEBUTTON]
EndFunc ; GUI_GetCloseButton()

#EndRegion API

The idea is to provide an interface to call into. The interface is all the user should interact with. The fact that the implementation uses a global variable is irrelevant.

Here's a better example of an interface and implementation that are separate that doesn't use global variables:

; ===================================================================
; Project: DocLib Library
; Description: Functions for building the AutoIt documentation.
; Author: Jason Boggs <vampire DOT valik AT gmail DOT com>
; ===================================================================
#include-once

#Region Members Exported
#cs Exported Functions
SciTE_Create() - Creates a SciTE object that can be used with SciTE_* functions. The handle returned must be destroyed with SciTE_Destroy().
SciTE_Destroy(ByRef $vHandle) - Destroys a SciTE handle created by SciTE_Create().
SciTE_OpenFile($vHandle, $sFile) - Opens the specified file in the SciTE instance.
SciTE_ExportAsHtml($vHandle, $sFile) - Exports the active file to the specified destination.
SciTE_CloseFile($vHandle) - Closes the active file.
SciTE_SendCommand($vHandle, $sCmd, $hResponse = 0) - Sends the specified command to the SciTE instance.
_FileListToArraySorted($sPath, $sFilter = "*", $iFlag = 0) - Returns a file list in a sorted array.
#ce Exported Functions
#EndRegion Members Exported

#Region Includes
#include <Array.au3>
#include <File.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
#EndRegion Includes

#Region Global Variables
Global Enum $SCITE_MAINHWND, $SCITE_DIRECTORHWND, $SCITE_MAX
#EndRegion Global Variables

#Region Library Initialization

#EndRegion Library Initialization

#Region Public Members

#Region SciTE Functions

#Region SciTE_Create()
; ===================================================================
; SciTE_Create()
;
; Creates a SciTE object that can be used with SciTE_* functions. The handle returned must
; be destroyed with SciTE_Destroy().
; Parameters:
;   None.
; Returns:
;   Success: A handle for use in other SciTE_* functions.
;   Failure: 0, sets @error to non-zero as follows:
;       1 - SciTE could not be found.
;       2 - The required properties file could not be found.
; ===================================================================
Func SciTE_Create()
    ; Get the ptah to the required files.
    Local $sSciTE = __SciTE_FindFile("SciTE.exe")
    Local $sPropertiesFile = __SciTE_FindFile("au3.keywords.properties")

    If Not $sSciTE Then Return SetError(1, 0, 0)
    If Not $sPropertiesFile Then Return SetError(2, 0, 0)

    ; The -import command requires the .properties extenstion to be stripped.
    $sPropertiesFile = StringTrimRight($sPropertiesFile, 11)

    ; Set SciTE_HOME to a directory that doesn't contain global/user properties
    ; files. This ensures the import statement works correctly.
    EnvSet("SciTE_HOME", @TempDir)

    ; Build the full command to start SciTE.
    $sSciTE = StringFormat('"%s" "-import %s" -check.if.already.open=0', $sSciTE, $sPropertiesFile)

    ; Run SciTE hidden and store the PID.
    Local $pid = Run($sSciTE)

    ; Build the handle to return.
    Local $vHandle[$SCITE_MAX]
    $vHandle[$SCITE_MAINHWND] = __SciTE_MainHWNDFromPID($pid)
    $vHandle[$SCITE_DIRECTORHWND] = __SciTE_DirectorHWNDFromPID($pid)

    ; Hide the SciTE window because it ignores @SW_HIDE.
    WinSetState($vHandle[$SCITE_MAINHWND], "", @SW_HIDE)

    ; Return the handle.
    Return $vHandle
EndFunc ; SciTE_Create()
#EndRegion SciTE_Create()

#Region SciTE_Destroy()
; ===================================================================
; SciTE_Destroy(ByRef $vHandle)
;
; Destroys a SciTE handle created by SciTE_Create().
; Parameters:
;   $vHandle - IN/OUT - The handle to SciTE.
; Returns:
;   Sets @error to non-zero if the handle was invalid.
; ===================================================================
Func SciTE_Destroy(ByRef $vHandle)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)
    SciTE_SendCommand($vHandle, "quit:")
    $vHandle = 0
EndFunc ; SciTE_Destroy()
#EndRegion SciTE_Destroy()

#Region SciTE_OpenFile()
; ===================================================================
; SciTE_OpenFile($vHandle, $sFile)
;
; Opens the specified file in the SciTE instance.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
;   $sFile - IN - The file to open.
; Returns:
;   Sets @error to non-zero if the handle was invalid.
; ===================================================================
Func SciTE_OpenFile($vHandle, $sFile)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)
    Return SciTE_SendCommand($vHandle, "open:" & StringReplace($sFile, "\", "\\"))
EndFunc ; SciTE_OpenFile()
#EndRegion SciTE_OpenFile()

#Region SciTE_ExportAsHtml()
; ===================================================================
; SciTE_ExportAsHtml($vHandle, $sFile)
;
; Exports the active file to the specified destination.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
;   $sFile - IN - The destination file to save to.
; Returns:
;   Sets @error to non-zero if the handle was invalid.
; ===================================================================
Func SciTE_ExportAsHtml($vHandle, $sFile)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)
    Return SciTE_SendCommand($vHandle, "exportashtml:" & StringReplace($sFile, "\", "\\"))
EndFunc ; SciTE_ExportAsHtml()
#EndRegion SciTE_ExportAsHtml()

#Region SciTE_CloseFile()
; ===================================================================
; SciTE_CloseFile($vHandle)
;
; Closes the active file.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
; Returns:
;   Sets @error to non-zero if the handle was invalid.
; ===================================================================
Func SciTE_CloseFile($vHandle)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)
    Return SciTE_SendCommand($vHandle, "close:")
EndFunc ; SciTE_CloseFile()
#EndRegion SciTE_CloseFile()

#Region SciTE_SendCommand()
; ===================================================================
; SciTE_SendCommand($vHandle, $sCmd, $hResponse = 0)
;
; Sends the specified command to the SciTE instance.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
;   $sCmd - IN - The command to send.
;   $hResponse - IN/OPTIONAL - The optional HWND to a window that will receive a response.
; Returns:
;   Sets @error to non-zero if the handle was invalid.
; ===================================================================
Func SciTE_SendCommand($vHandle, $sCmd, $hResponse = 0)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)

    ; Create a string to hold the command.
    Local $tCmd = DllStructCreate(StringFormat("char[%d]", StringLen($sCmd) + 1))
    DllStructSetData($tCmd, 1, $sCmd)

    ; Create the COPYDATA structure.
    Local $tCopyDataStruct = DllStructCreate("ULONG_PTR dwData; DWORD cbData; ptr lpData;")
    DllStructSetData($tCopyDataStruct, "dwData", 1)
    DllStructSetData($tCopyDataStruct, "cbData", StringLen($sCmd) + 1)
    DllStructSetData($tCopyDataStruct, "lpData", DllStructGetPtr($tCmd))

    ; Send the command.
    Return _SendMessageA(__SciTE_GetDirectorHWND($vHandle), $WM_COPYDATA, $hResponse, DllStructGetPtr($tCopyDataStruct), 0, "hwnd", "ptr")
EndFunc ; SciTE_SendCommand()
#EndRegion SciTE_SendCommand()

#EndRegion SciTE Functions

#Region _FileListToArraySorted()
; ===================================================================
; _FileListToArraySorted($sPath, $sFilter = "*", $iFlag = 0)
;
; Returns a file list in a sorted array.
; Parameters:
;   $sPath - IN - The root path to search.
;   $sFilter - IN/OPTIONAL - The file filter to search for.
;   $iFlag - IN/OPTIONAL - Specifies whether to return files folders or both:
;       0 - Return both files and folders (Default).
;       1 - Return files only.
;       2 - Return Folders only
; Returns:
;   Sucess: A sorted array.
;   Failure: 0, sets @error to non-zero.
; ===================================================================
Func _FileListToArraySorted($sPath, $sFilter = "*", $iFlag = 0)
    Local $aFiles = _FileListToArray($sPath, $sFilter, $iFlag)
    Local Const $nError = @error, $nExtended = @extended
    _ArraySort($aFiles, 0, 1)
    Return SetError($nError, $nExtended, $aFiles)
EndFunc ; _FileListToArraySorted()
#EndRegion _FileListToArraySorted()

#EndRegion Public Members

#Region Private Members

#Region SciTE Private Functions

#Region __SciTE_FindFile()
; ===================================================================
; __SciTE_FindFile($sFile)
;
; Searches for the specified file in the standard SciTE locations.
; Parameters:
;   $sFile - IN - The filename to search for.
; Returns:
;   Success - The path to the specified file.
;   Failure - An empty string.
; ===================================================================
Func __SciTE_FindFile($sFile)
    ; Look for the file relative to docs\build.
    Local $sLocation = "..\..\install\SciTE\" & $sFile
    If Not FileExists($sLocation) Then
        ; Look for the file in the AutoIt SciTE directory.
        $sLocation = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\AutoIt v3\AutoIt", "InstallDir") & "\SciTE\" & $sFile

        ; Return an empty string if the file was not found.
        If Not FileExists($sLocation) Then Return ""
    EndIf

    ; Return the location if the file was found.
    Return $sLocation
EndFunc ; __SciTE_FindFile()
#EndRegion __SciTE_FindFile()

#Region __SciTE_GetMainHWND()
; ===================================================================
; __SciTE_GetMainHWND($vHandle)
;
; Retrieves the SciTE window handle.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
; Returns:
;   Success - The SciTE window handle.
;   Failure - 0, sets @error to non-zero.
; ===================================================================
Func __SciTE_GetMainHWND($vHandle)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)
    Return $vHandle[$SCITE_MAINHWND]
EndFunc ; __SciTE_GetMainHWND()
#EndRegion __SciTE_GetMainHWND()

#Region __SciTE_GetDirectorHWND()
; ===================================================================
; __SciTE_GetDirectorHWND($vHandle)
;
; Retrieves the SciTE Director window handle.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
; Returns:
;   Success - The SciTE Director window handle.
;   Failure - 0, sets @error to non-zero.
; ===================================================================
Func __SciTE_GetDirectorHWND($vHandle)
    If Not __SciTE_IsValid($vHandle) Then Return SetError(-1, 0, 0)
    Return $vHandle[$SCITE_DIRECTORHWND]
EndFunc ; __SciTE_GetDirectorHWND()
#EndRegion __SciTE_GetDirectorHWND()

#Region __SciTE_MainHWNDFromPID()
; ===================================================================
; __SciTE_MainHWNDFromPID($pid)
;
; Retrieves the SciTE window from the specified PID.
; Parameters:
;   $pid - IN - The PID to get the SciTE window from.
; Returns:
;   Success - The handle to the SciTE window.
;   Failure - 0.
; ===================================================================
Func __SciTE_MainHWNDFromPID($pid)
    Return __SciTE_HWNDFromPID($pid, "[CLASS:SciTEWindow]")
EndFunc ; __SciTE_MainHWNDFromPID()
#EndRegion __SciTE_MainHWNDFromPID()

#Region __SciTE_DirectorHWNDFromPID()
; ===================================================================
; __SciTE_DirectorHWNDFromPID($pid)
;
; Retrieves the SciTE Director window from the specified PID.
; Parameters:
;   $pid - IN - The PID to get the SciTE Director window from.
; Returns:
;   Success - The handle to the SciTE Director window.
;   Failure - 0.
; ===================================================================
Func __SciTE_DirectorHWNDFromPID($pid)
    Return __SciTE_HWNDFromPID($pid, "[CLASS:DirectorExtension]")
EndFunc ; __SciTE_DirectorHWNDFromPID()
#EndRegion __SciTE_DirectorHWNDFromPID()

#Region __SciTE_HWNDFromPID()
; ===================================================================
; __SciTE_HWNDFromPID($pid, $sWindowDescription, $nTimeout = 5000)
;
; Description.
; Parameters:
;   $pid - IN - The PID to get the window from.
;   $sWindowDescription - IN - An advanced window description of the window.
;   $nTimeout - IN/OPTIONAL - How long to wait for the window before giving up.
; Returns:
;   Success - The handle to the specified window.
;   Failure - 0.
; ===================================================================
Func __SciTE_HWNDFromPID($pid, $sWindowDescription, $nTimeout = 5000)
    Local $nStart = TimerInit()
    While TimerDiff($nStart) < $nTimeout
        Local $aList = WinList($sWindowDescription)
        For $i = 1 To UBound($aList) - 1
            If WinGetProcess($aList[$i][1]) = $pid Then Return $aList[$i][1]
        Next
        Sleep(250)
    WEnd
    Return 0
EndFunc ; __SciTE_HWNDFromPID()
#EndRegion __SciTE_HWNDFromPID()

#Region __SciTE_IsValid()
; ===================================================================
; __SciTE_IsValid($vHandle)
;
; Tests if the specified handle is valid.
; Parameters:
;   $vHandle - IN - The handle to SciTE.
; Returns:
;   True - The handle is valid.
;   False - The handle is not valid.
; ===================================================================
Func __SciTE_IsValid($vHandle)
    Return UBound($vHandle) = $SCITE_MAX
EndFunc ; __SciTE_IsValid()
#EndRegion __SciTE_IsValid()

#EndRegion SciTE Private Functions

#EndRegion Private Members

SciTE_Create() returns an opaque handle. The caller doesn't need to worry about what the handle really is, they just pass it to other SciTE_* functions. Even the SciTE_* functions aren't bound to an implementation. If SciTE had a COM interface I could easily change the code to use the COM interface and wouldn't have to touch a single line in any of the SciTE_* functions nor would the caller of the SciTE_* functions need to be changed. Only the __SciTE functions would change because they are the only parts of the code that deal with the implementation.

A design like this is far more flexible and future-proof than a design using global variables. I have pushed all the nasty details far away from where things are used. Things are abstracted away into concepts. The caller only wants to automate SciTE, the caller doesn't care if it uses messages, window automation, a COM interface or command line arguments. The interface doesn't care about those details, either. It only exists to provide an access point between the caller and the raw implementation of the behavior.

2 people like this

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

So... Does this mean you are better off with lots of locals or a few globals? One of things I like about OnEvent mode is that you don't need to make nearly as many variables, but the few you do need must be global.

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

whatever Edited by MvGulik

"Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions."
"The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014)

"Believing what you know ain't so" ...

Knock Knock ...
 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0